命名规则 (程式设计)

程式设计的中命名规则(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的命名规则是由多个社区制定的,包括Sun微系统[14]、网景[15]、AmbySoft[16] 等等。下述采用Sun微系统制定规则的例子, 比如 "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). 

外部链接