代码风格

代码风格（Programming style）即程序开发人员所编写源代码的书写风格。良好的代码风格会帮助程序员阅读和理解符合该风格的源代码，并且避免错误。

关于该主题的经典著作是 1970 年代编写的《编程风格的要素》，并以当时流行的 Fortran 和 PL/I 语言的示例进行了说明。

特定程序中使用的编程风格可能源自公司或其他计算组织的代码约定，以及代码作者的偏好。编程风格通常是为特定的编程语言（或语言家族）设计的：在 C 源代码中被认为是良好的风格可能不适合 BASIC 源代码等等。但是，一些规则通常适用于许多语言。

## 良好风格的要素

总结程序设计实践中的经验，代码风格的要素包括（但不限于）以下几点：

- 名字的使用（参见：驼峰式大小写、标识符命名约定、匈牙利命名法）
- 表达式与语句
- 常量的使用
- 注释的使用
- 缩进（参见：缩进风格）
- 代码的布局

## 代码外观

代码风格通常处理源代码的可视外观，带有可读性的目标。软件很长时间都可以格式化源代码，让写代码的人将注意力集中在命名，逻辑和更高级的技术。作为一个实际的点，用计算机来格式化源代码节省了时间，且使不带网络论战地实施全公司的标准成为可能。

### 缩进

缩进风格协助确认控制流和代码块。在一些编程语言中，缩进被用来限定代码的逻辑块；在这些情况下正确的缩进不仅仅是风格的事。在其他语言中，缩进和空白字符不影响功能，虽然有逻辑和一贯的缩进是代码更易于阅读。比较：

```c++
if (hours < 24 && minutes < 60 && seconds < 60) {
    return true;
} else {
    return false;
}
```

或

```c++
if (hours < 24 && minutes < 60 && seconds < 60)
{
    return true;
}
else
{
    return false;
}
```

和像是这样

```c++
if  ( hours   < 24
   && minutes < 60
   && seconds < 60
)
{return    true
;}         else
{return   false
;}
```

前两个示例很可能更容易阅读，因为它们以既定的方式缩进（"hanging paragraph" 样式）。这种缩进风格在处理多个嵌套结构时特别有用。

#### ModuLiq

ModuLiq Zero 缩进风格用回车分组而不是缩进。和所有以上的比较：

```c++
if (hours < 24 && minutes < 60 && seconds < 60)
return true;

else
return false;
```

#### Lua

Lua不用传统的花括号和括号。if/else 语句只需要表达式后面有`then`，以`end`结束 if/else 语句。

```lua
if hours < 24 and minutes < 60 and seconds < 60 then
  return true
else
  return false
end
```

缩进是可选的。`and`,`or`,`not`在 true/false 语句间被使用。

它们是真/假陈述，如

```lua
print(not true)
```

会代表假。

#### Python

Python 用缩进来表明控制结构，所以正确的缩进是需要的。通过这么做，用花括号（亦即`{`和`}`）包括的需要就被清除。另一方面，复制和粘贴 Python 代码可能导致问题，因为被粘贴的代码的缩进级别可能和当前行的缩进级别不同。这样的重格式化用手做可能十分乏味，但一些文本编辑器和集成开发环境有自动做的功能。也有当 Python 代码被发表在去除空白字符的论坛或网页上，使它变得无法使用的问题，虽然这个问题可以在能用保留空白字符的标签，像" ... "（HTML中），"code"..."/code"（bbcode中）等等时避免。

```python3
if hours < 24 and minutes < 60 and seconds < 60:
    return True
else:
    return False
```

注意 Python 不适用花括号，而是一个普通的英文冒号（例子`else:`）。

许多 Python 程序员倾向于遵循一种公认的风格指南，称为 PEP8。有一些工具旨在自动化 PEP8 合规性。

#### Haskell

Haskell 类似地有越位规则，也就是它有一种二维语法，在其中缩进对定义块有意义（虽然另一种语法用花括号和分号）。Haskell 是一种声明式语言，在 Haskell 脚本中有语句，但是有声明。示例:

```haskell
let c_1 = 1
    c_2 = 2
in
    f x y = c_1 * x + c_2 * y
```

可以被写成一行，如：

```haskell
let {c_1=1;c_2=2} in f x y = c_1 * x + c_2 * y
```

Haskell 鼓励 文学编程 的使用，扩展的文本解释代码的缘由。在文学式 Haskell 脚本（带有扩展名`lhs`）中，所有东西都是注释，除了标记为代码的块。程序可以用 LaTeX 编写，这种情况下 `code` 环境标记哪里是代码。并且每个活动的代码段落可以被在前面和后面带上空行的方式标记，以一个大于号和一个空格开始每一行代码。这里有一个使用 LaTeX 标记的：

```haskell
The function \verb+isValidDate+ test if date is valid
\begin{code}
isValidDate :: Date -> Bool
isValidDate date = hh>=0  && mm>=0 && ss>=0
                 && hh<24 && mm<60 && ss<60
 where (hh,mm,ss) = fromDate date
\end{code}
observe that in this case the overloaded function is \verb+fromDate :: Date -> (Int,Int,Int)+.
```

一个使用纯文本的例子：

```haskell
The function isValidDate test if date is valid

> isValidDate :: Date -> Bool
> isValidDate date = hh>=0  && mm>=0 && ss>=0
>                  && hh<24 && mm<60 && ss<60
>  where (hh,mm,ss) = fromDate date

observe that in this case the overloaded function is fromDate :: Date -> (Int,Int,Int).
```

#### 垂直对齐

将相似的元素垂直对齐经常是有帮助的，使错字导致的错误更加明显。比较：

```php
$search = array('a', 'b', 'c', 'd', 'e');
$replacement = array('foo', 'bar', 'baz', 'quux');

// Another example:

$value = 0;
$anothervalue = 1;
$yetanothervalue = 2;
```

和

```php
$search      = array('a',   'b',   'c',   'd',   'e');
$replacement = array('foo', 'bar', 'baz', 'quux');

// Another example:

$value           = 0;
$anothervalue    = 1;
$yetanothervalue = 2;
```

#### 空格

在一些需要空白字符的情况下，绝大部分自由形式语言的语法不关心出现了多少空白字符。与空白字符相关的风格被普遍用来加强可读性。目前没有已知的确凿事实（研究得出的结论）关于哪种空白字符风格有最好的可读性。

例如，比较下列语法上等价的 C 语言代码例子：

```c
int i;
for(i=0;i<10;++i){
    printf("%d",i*i+i);
}
```

v.s.

```c
int i;
for (i = 0; i < 10; ++i) {
    printf("%d", i * i + i);
}
```

#### 制表符

使用制表键来创建空白字符，在不施加足够关注时会造成特定的问题，因为依据使用的工具，甚至是用户的偏好，制表点的位置可能不同。

如一个例子，一个程序员偏好4个制表位，将工具集设置成如此，然后用这些去格式化代码。

```c++
int     ix;     // Index to scan array
long    sum;    // Accumulator for sum
```

另一个程序员偏好8个制表位，并将工具集设置成如此。当其他人检查原来那个人的代码时，他们可能会发现很难读。

```c++
int             ix;             // Index to scan array
long    sum;    // Accumulator for sum
```

一种对这个问题广泛使用的解决方法可能包含不为对齐使用制表键，或制定必须设置成几个制表位的规则。注意制表符在一贯的情况下工作良好，限制在局部缩进上，并且不用来对齐：

```c++
class MyClass {
	int foobar(
		int qux, // first parameter
		int quux); // second parameter
	int foobar2(
		int qux, // first parameter
		int quux, // second parameter
		int quuux); // third parameter
};
```

## 参见

- C and C++ Style Guides
- Programming in C++, Rules and Recommendations
- Aladdin's C coding guidelines
- USER NOTES ON FORTRAN PROGRAMMING (UNFP)
- PROGRAM LAYOUT - THE ART OF MAKING PROGRAMS READABLE