命名規則 (程式設計)

程式設計的中命名規則(naming convention)是電腦程式設計原始碼針對識別碼的名稱字串進行定義(即「命名」)而規定的一系列規則。通常是為了提高原始碼的易讀性、易認性、程式效率以及可維護性。命名規則根據各個程式語言的規格、主記憶體大小等硬件制約、編輯器以及整合式開發環境的功能等等會有各種制約。

制定命名規則的好處

挑戰

命名規則的選擇(及其執行的程度)通常是一個有爭議的問題,不同派系的人會覺得自己的觀點最好而其他人則是次等的。 而且,即使採用了已知且定義明確的命名規則,某些組織也可能無法始終如一地遵守這些規則,從而導致不一致和混亂。 如果命名規則在內部不一致、任意、難記,或者以其他方式顯得負擔大於好處,則命名規則會遇到更多的挑戰。

易讀性

精細挑選的識別碼可以讓開發者和剖析器更容易理解系統在做什麼,或者如何修改或將原始碼擴充運用到新需求上。 比如這句聲明

 a = b * c;

在語意上是正確的,但是其目的卻不明顯。而相比較之下,寫成

 weekly_pay = hours_worked * hourly_pay_rate;

則提示了原始碼的意圖和含義,至少對了解上下文的人來說更清晰。

典型要素

識別碼長度

最基本的規則中包括對識別碼長度的規定。在某些情況下,上限是通過提供數值來設置的,而另一些情況下則使用了啟發式的方法或準則。

識別碼長度的規則是有爭議的,適當的長度應視具體情況而定。

要考慮的要點包括:

  • 較短的識別碼可能比較好,因為它更容易鍵入。(儘管許多IDE和文字編輯器都提供了文字補全功能,這可以緩解這種情況)
  • 太短的識別碼(例如a和i)很難使用自動搜尋和替換工具來唯一區分。
  • 在某些情況下,最好使用長識別碼,因為短識別碼無法包含足夠的語義資訊。
  • 縮寫可能令人困惑,應避免使用,但是太長的正式名稱也會因損害代碼可讀性而不受歡迎。

一些早期的連結器將變數名限制為6個字元或更少,以減少主記憶體使用,這也是早期的程式會限制識別碼長度的原因之一。

大小寫和數字

一些命名規則對大小寫和數字的使用加以限制,比如只能用小寫字母,或者只能用大寫字母。有些場合雖然可以保留大小寫,但功能上並不賦予區別。

多個單詞組成的識別碼

通常推薦使用「有實際含義的識別碼」。如果單個單詞無法表述清晰則可以使用多個單詞,因此命名規則需要規定多個單詞如何連接。這樣還可以避免與各個程式語言使用的保留字衝突的問題。大多數語言的識別碼不允許空格,而不加空格又會導致難以閱讀,因此需要制定空格的替代方式。

用符號區分

在字母數字的單詞裏使用制定的區分字元進行連接,常用有 連字元 ("-") 、底線 ("_"),比如兩個單詞的 "two words" 可寫成 "two-words" 或者 "two_words"。連字元非常常用,包括 COBOL (1959), Forth (1970)以及 Lisp (1958),而在 Unix 命令和包里也很常見。在 CSS 中也是如此。[1] 這種做法沒有一個通稱,有人叫 lisp-case 或者 COBOL-CASE (是為了與 Pascal case 相區別),或者叫 kebab-casebrochette-case等等。[2][3][4][5] 但至少是從 2012 年之後,[6]  kebab-case 這個叫法越來越流行。[7][8]

與此相比,在 FORTRAN/ALGOL 語言的傳統中,特別是 C語言 和 Pascal語言 家族,曾使用連接號用於 中綴表示法 的減法運算子,而且也不希望前後加空格, 因此就無法用此方法來命名識別碼。而用底線連接小寫字母的方法則在 C 家族(包括 Python)里都很常見,比如 The C Programming Language (1978) 即可見到,通稱為 snake case. 而像 UPPER_CASE 這樣用底線連接大寫字母的做法則常見於 C預處理器 里的宏,所以被稱為 MACRO_CASE;以及 Unix 中的 環境變數,比如 bash 里的BASH_VERSION。有時會被幽默地稱作 SCREAMING_SNAKE_CASE。

用大小寫區分

另一種做法就是在單詞組合成一個字串的中間使用大寫字母,被稱作駝峰式大小寫"(camelCase)或者 "Pascal case"等等,也就把 "two words" 寫成 "twoWords" 或者 "TwoWords"。這種方式常見於 PascalJava, C#以及Visual Basic。而對於首字母縮寫詞的處理方式仍會不一樣。(比如 XMLHttpRequest 中的 "XML" 和 "HTTP),有些會用小寫以易於打字和閱讀(比如 XmlHttpRequest)而有些會保持大寫以保證準確性(如寫成XMLHTTPRequest)。

元數據與混合命名規則

有一些命名規則不僅是特定程式、某個特定專案和問題的規則和需求,還通過軟件架構稱為對其下層的程式語言和跨專案的一個方法論框架。

匈牙利命名法

最著名的命名規則包括匈牙利命名法,具體包括「系統匈牙利命名法」和「匈牙利應用命名法」[9]。比如變數 szName 中的字首 "sz" 代表其是一個零結束字串。

各種語言的命名規則

C 和 C++

原則上使用小寫字母。在C標準庫里,最常用的做法是使用縮寫名稱,如用於測試是字元是否為字母數字的函數寫成 isalnum ,而C++的標準庫了則常用底線作為單詞分隔符(如 out_of_range)。而C預處理的識別碼則只用大寫字母和底線(因為很多程式語言都用全大寫標示常數),帶兩個底線或者以底線和一個大寫字母打頭的名字都預留給編譯器,因此都不能用(比如 __reserved 或者 _Reserved)。[10][11] 雖然這表面上與 stropping英語Stropping (syntax) 類似,但語意上完全不同,因為底線是識別碼的值的一部分,而不是 stropping 那樣只是表示參照: __foo 的值是 __foo (被預留),而不是 foo(但是在一個不同的命名空間)。

C#

C# 命名規則基本上遵循微軟的 .NET 語言的規範。[12] (詳見後續 .NET 章節),但 C# 編譯器並不強制使用命名規則。微軟推薦僅用 PascalCasecamelCase,後者僅用於方法參數和本地方法變數名(包括本地方法 const 值)。一個不適用 PascalCase 的特例,是識別碼開頭的雙字母首字母縮寫詞,這時兩個字母都要大寫,如 IOStream,但這不適用於更長的首字母縮寫詞裏,如 XmlStream。該規範還推薦 interface 的名字要用 PascalCase 並在開頭加一個大寫字母 I,如 IEnumerable

微軟規範對 filed 命名僅限於 static, public 和 protected,並明確指出如果非靜態、或者有其他可接入層級(比如 internalprivate)則不在規範範圍之內。[13] 最常用的做法是所有 filed 都使用 PascalCase ,而只有 private (且  conststatic),這些例外使用 camelCase 並添加一個底線,如 _totalCount

識別碼可以添加 @ 符號卻不改變含義。也就是說  factor@factor 均指同一個對象。在規則上,這一字首僅用於當該識別碼是預留關鍵詞(比如 forwhile,不加字首就不能當成識別碼),或者是有上下文關鍵詞(比如 fromwhere,並不嚴格要求有字首,至少不是所有聲明都要求,比如儘管 dynamic dynamic; 聲明有效,但這會被看作 dynamic @dynamic; 以讓讀者立即知道後者是一個變數名)。

Java

Java的命名規則是由多個社區制定的,包括太陽電腦[14]、網景[15]、AmbySoft[16] 等等。下述採用太陽電腦制定規則的例子, 比如 "CamelCase",不用空格直接連起來,每個單詞首字母大寫,比如 "CamelCase".

識別碼類型 命名規則 舉例
應該為名詞,用 UpperCamelCase,即每個詞首字母大寫,拼寫完整,不用簡稱、縮寫(除非縮寫比全名更常用,如 URL 或 HTML)
  • class Raster {}
  • class ImageSprite {}
方法 應該用動詞,用 lowerCamelCase,或者用一個小寫動詞打頭的詞組,即首字母小寫,之後的每個詞首字母大寫。
  • run();
  • runFast();
  • getBackground();
變數 本地變數、即時變數和類別變數也用 lowerCamelCase。變數名不能以底線 (_) 或美元符號 ($) 打頭,這與其他編碼規則里採用底線追尾所有即時變數字首的規定不同。

變數名稱應該簡潔易懂,便於記憶。儘量避免使用單字母,除非一些臨時變數。臨時變數常用名,整數型一般用 i, j, k, m 或 n;而字元型則用 c, d 或 e。

  • int i;
  • char c;
  • float myWidth;
常數 用大寫字母,並用底線隔開。 可以用數字,但不能為首字元。
  • static final int MAX_PARTICIPANTS = 10;


縮寫詞長達三個字母及其以上時用 CamelCase 而不是全大寫(比如 parseDbmXmlFromIPAddress 不寫作parseDBMXMLFromIPAddress),這個規則可以適用至兩個字母詞 (如 parseDbmXmlFromIpAddress).


JavaScript

JavaScript 的內建庫採用與 Java 同樣的命名規則。資料類型和建造函數使用 upper camel case (RegExp, TypeError, XMLHttpRequest, DOMObject) 而方法使用 lower camel case (getElementById, getElementsByTagNameNS, createCDATASection)。為了保持統一,大部分 JavaScript 開發者都遵循此命名規則。[17]

.NET

微軟公司 Microsoft .NET 推薦大部分識別碼都用 UpperCamelCase(而參數和變數推薦用 lowerCamelCase) 這是所有 .NET 語言的通則,[18] 微軟還推薦無需使用(匈牙利命名法那樣的)字首提示,[19] 而是推薦在後面加上基礎類名,如寫成 LoginButton 而不是 BtnLogin[20]

Objective-C

Objective-C 使用源於 Smalltalk 的代碼方式。通用的變數、函數的頂層條目,包括類、協定都用 UpperCamelCase 並用一個短的全大寫字首標示命名空間,比如 NSString, UIAppDelegate, NSApp 以及 CGRectMake。常數可以有小寫字母k打頭的字首如 kCFBooleanTrue。 即時對象的變數使用帶底線的 lowerCamelCase,如 _delegate and _tableView。Method 名使用多個 lowerCamelCase 並用冒號區分如 application:didFinishLaunchingWithOptions:, stringWithFormat: and isRunning.

Perl

Perl 繼承了C中的一些規則。本地範圍內的變數和子程式名用小寫字母加底線。包變數採用 title case,聲明的常數全大寫。包的名字採用 camel case 但 pragmata 例外,比如 strictmro用小寫。 [21] [22]

PHP

PHP 推薦方式寫在 PSR-1 (PHP Standard Recommendation 1) 和 PSR-12 中。[23] 根據 PSR-1,類的名字要用 PascalCase, 類的常數要用 MACRO_CASE,而 method 名要用 camelCase。[24]

Python and Ruby

PythonRuby都推薦類名使用 UpperCamelCase,常數名使用 CAPITALIZED_WITH_UNDERSCORES,其他名字用 lowercase_separated_by_underscores

Swift

Swift語言的命名規則根據不同發佈有所變化。但是隨着 Swift 3.0 的重大更新後,其命名規則規範更為清晰,希望能對所有第三方的 API 命名和聲明規則進行標準化[25]。變數、函數聲明的命名規則還是以 lowerCamelCase 為基礎。常數通常使用 enum 類型定義。類和其他類型的聲明採用 UpperCamelCase

參見


註釋

  1. ^ CSS reference. Mozilla Developer Network. [2016-06-18]. (原始內容存檔於2021-01-13). 
  2. ^ StackOverflow – What's the name for snake_case with dashes?. [2020-05-21]. (原始內容存檔於2014-12-26). 
  3. ^ Programmers – If this is camelCase what-is-this?. [2020-05-21]. (原始內容存檔於2016-08-07). 
  4. ^ Camel_SNAKE-kebab. September 2019 [2020-05-21]. (原始內容存檔於2018-06-11). 
  5. ^ UnderscoreVersusCapitalAndLowerCaseVariableNaming. [2020-05-21]. (原始內容存檔於2015-10-02). 
  6. ^ jwfearn. Revisions to jwfearn's answer to What's the name for dash-separated case?. 5 September 2012 [2020-05-21]. (原始內容存檔於2017-05-10). 
  7. ^ Living Clojure (2015), by Carin Meier, p. 91頁面存檔備份,存於互聯網檔案館
  8. ^ lodash: kebabCase. [2020-05-21]. (原始內容存檔於2021-01-08). 
  9. ^ Making Wrong Code Look Wrong. 11 May 2005 [2020-05-21]. (原始內容存檔於2016-11-22). 
  10. ^ ISO/IEC 9899:1999 Programming languages – C. ISO. [2020-05-21]. (原始內容存檔於2017-01-29). 
  11. ^ ISO/IEC 14882:2011 Information technology – Programming languages – C++. ISO. [2020-05-21]. (原始內容存檔於2013-05-17). 
  12. ^ Naming Guidelines. Microsoft. [2020-05-21]. (原始內容存檔於2020-11-17). 
  13. ^ Names of Type Members. Microsoft. [2020-05-21]. (原始內容存檔於2020-11-14). 
  14. ^ "Code Conventions for the Java Programming Language", Section 9: "Naming Conventions"頁面存檔備份,存於互聯網檔案館
  15. ^ "NETSCAPE'S SOFTWARE CODING STANDARDS GUIDE FOR JAVA",Collab Software Coding Standards Guide for Java頁面存檔備份,存於互聯網檔案館
  16. ^ "AmbySoft Inc. Coding Standards for Java v17.01d". [2020-05-21]. (原始內容存檔於2020-08-20). 
  17. ^ Morelli, Brandon. 5 JavaScript Style Guides – Including AirBnB, GitHub, & Google. codeburst.io. 17 November 2017 [17 August 2018]. (原始內容存檔於2017-11-12). 
  18. ^ Microsoft .NET Framework Capitalization Styles. [2020-05-21]. (原始內容存檔於2017-03-24). 
  19. ^ .NET Framework Developer's Guide – General Naming Conventions. [2020-05-21]. (原始內容存檔於2016-03-03). 
  20. ^ [Framework Design Guidelines, Krzysztof Cwalina, Brad Abrams Page 62]
  21. ^ Perl style guide. [2020-05-21]. (原始內容存檔於2013-06-26). 
  22. ^ perlmodlib – constructing new Perl modules and finding existing ones. [2020-05-21]. (原始內容存檔於2020-06-28). 
  23. ^ PHP standards recommendations. [2020-05-21]. (原始內容存檔於2020-11-12). 
  24. ^ 存档副本. [2020-05-21]. (原始內容存檔於2019-03-31). 
  25. ^ swift.org API Design Guidelines. [2020-05-21]. (原始內容存檔於2021-01-12). 

外部連結