代碼風格

代碼風格（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