命名规则 (程序设计)

程序设计的中命名规则（naming convention）是电脑程序设计的源代码针对标识符的名称字符串进行定义（即“命名”）而规定的一系列规则。通常是为了提高源代码的易读性、易认性、程序效率以及可维护性。命名规则根据各个程序语言的规格、内存大小等硬件制约、编辑器以及集成开发环境的功能等等会有各种制约。

## 挑战

命名规则的选择（及其执行的程度）通常是一个有争议的问题，不同派系的人会觉得自己的观点最好而其他人则是次等的。而且，即使采用了已知且定义明确的命名规则，某些组织也可能无法始终如一地遵守这些规则，从而导致不一致和混乱。如果命名规则在内部不一致、任意、难记，或者以其他方式显得负担大于好处，则命名规则会遇到更多的挑战。

## 易读性

精细挑选的标识符可以让开发者和分析器更容易理解系统在做什么，或者如何修改或将源代码扩展运用到新需求上。比如这句声明

```C
 a = b * c;
```

在语义上是正确的，但是其目的却不明显。而相比较之下，写成

```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 中也是如此。这种做法没有一个通称，有人叫 lisp-case 或者 COBOL-CASE （是为了与 Pascal case 相区别），或者叫 kebab-case、brochette-case等等。但至少是从 2012 年之后，kebab-case 这个叫法越来越流行。

与此相比，在 FORTRAN/ALGOL 语言的传统中，特别是C语言和Pascal语言家族，曾使用连接号用于 中缀表示法 的减法运算符，而且也不希望前后加空格, 因此就无法用此方法来命名标识符。而用下划线连接小写字母的方法则在 C 家族（包括 Python）里都很常见，比如《C程序设计语言》（1978）即可见到，通称为蛇形命名法（snake_case）。而像 UPPER_CASE 这样用下划线连接大写字母的做法则常见于 C预处理器 里的宏，所以被称为 MACRO_CASE；以及 Unix 中的 环境变量，比如 bash 里的BASH_VERSION。有时会被幽默地称作 SCREAMING_SNAKE_CASE。

#### 用大小写区分

另一种做法就是在单词组合成一个字符串的中间使用大写字母，被称作驼峰式大小写（camelCase）或者“Pascal case”等等，也就把 "`two words`" 写成 "`twoWords`" 或者 "`TwoWords`"。这种方式常见于 Pascal、Java, C♯以及Visual Basic。而对于首字母缩写词的处理方式仍会不一样。（比如 `XMLHttpRequest` 中的 "XML" 和 "HTTP），有些会用小写以易于打字和阅读（比如 `XmlHttpRequest`）而有些会保持大写以保证准确性（如写成`XMLHTTPRequest`）。

## 元数据与混合命名规则

有一些命名规则不仅是特定程序、某个特定项目和问题的规则和需求，还通过软件架构称为对其下层的程序语言和跨项目的一个方法论框架。

### 匈牙利命名法

最著名的命名规则包括匈牙利命名法，具体包括“系统匈牙利命名法”和“匈牙利应用命名法”。比如变量 szName 中的前缀 "sz" 代表其是一个零结束字符串。

## 各种语言的命名规则

### C 和 C++

原则上使用小写字母。在C标准库里，最常用的做法是使用缩写名称，如用于测试是字符是否为字母数字的函数写成 `isalnum`，而C++的标准库了则常用下划线作为单词分隔符（如 `out_of_range`）。而C预处理的标识符则只用大写字母和下划线（因为很多程序语言都用全大写标示常量），带两个下划线或者以下划线和一个大写字母打头的名字都预留给编译器，因此都不能用（比如 `__reserved` 或者 `_Reserved`）。虽然这表面上与 stropping 类似，但语义上完全不同，因为下划线是标识符的值的一部分，而不是 stropping 那样只是表示引用： `__foo` 的值是 `__foo` （被预留），而不是 `foo`（但是在一个不同的命名空间）。

### C#

C♯命名规则基本上遵循微软的 .NET 语言的规范。（详见后续 .NET 章节），但 C# 编译器并不强制使用命名规则。微软推荐仅用 `PascalCase` 和 camelCase，后者仅用于方法参数和本地方法变量名（包括本地方法 `const` 值）。一个不适用 PascalCase 的特例，是标识符开头的双字母首字母缩写词，这时两个字母都要大写，如 `IOStream`，但这不适用于更长的首字母缩写词里，如 `XmlStream`。该规范还推荐 `interface` 的名字要用 `PascalCase` 并在开头加一个大写字母 `I`，如 `IEnumerable`。

微软规范对 filed 命名仅限于 `static`, `public` 和 `protected`，并明确指出如果非静态、或者有其他可接入层级（比如 `internal` 和 `private`）则不在规范范围之内。最常用的做法是所有 filed 都使用 PascalCase，而只有 `private` （且 `const` 或 `static`），这些例外使用 camelCase 并添加一个下划线，如 `_totalCount`。

标识符可以添加 @ 符号却不改变含义。也就是说 `factor` 和 `@factor` 均指同一个对象。在规则上，这一前缀仅用于当该标识符是预留关键词（比如 `for` 和 `while`，不加前缀就不能当成标识符），或者是有上下文关键词（比如 `from` 和 `where`，并不严格要求有前缀，至少不是所有声明都要求，比如尽管 `dynamic&nbsp;dynamic;` 声明有效，但这会被看作 `dynamic&nbsp;@dynamic;` 以让读者立即知道后者是一个变量名）。

### Java

Java的命名规则是由多个社区制定的，包括太阳微系统、网景、AmbySoft等等。下述采用太阳微系统制定规则的例子，比如 "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 开发者都遵循此命名规则。

### .NET

微软公司Microsoft .NET 推荐大部分标识符都用 `UpperCamelCase`（而参数和变量推荐用 lowerCamelCase) 这是所有 .NET 语言的通则，微软还推荐无需使用（匈牙利命名法那样的）前缀提示，而是推荐在后面加上基础类名，如写成 `LoginButton` 而不是 `BtnLogin`。

### 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 例外，比如 `strict` 和 `mro`用小写。

### PHP

PHP推荐方式写在 PSR-1 (PHP Standard Recommendation 1) 和 PSR-12 中。根据 PSR-1，类的名字要用 PascalCase, 类的常数要用 MACRO_CASE，而 method 名要用 camelCase。

### Python and Ruby

Python和Ruby都推荐类名使用 `UpperCamelCase`，常数名使用 `CAPITALIZED_WITH_UNDERSCORES`，其他名字用 `lowercase_separated_by_underscores`。

### Swift

Swift语言的命名规则根据不同发布有所变化。但是随着 Swift 3.0 的重大更新后，其命名规则规范更为清晰，希望能对所有第三方的 API 命名和声明规则进行标准化。变量、函数声明的命名规则还是以 `lowerCamelCase` 为基础。常数通常使用 enum 类型定义。类和其他类型的声明采用 `UpperCamelCase`。

## 外部链接

- American Name Society – promotes onomastics, the study of names and naming practices, both in the United States and abroad.
- coding-guidelines.com has a pdf that uses linguistics and psychology to attempt a cost/benefit analysis of identifier naming issues