1. 程式人生 > 實用技巧 >《編寫可讀程式碼的藝術》第7章 簡化迴圈和邏輯

《編寫可讀程式碼的藝術》第7章 簡化迴圈和邏輯

1. 條件語句中引數的順序

左邊更傾向於使用變化的,右邊更傾向於使用穩定的。

1 if (length >= 10)
2 // or
3 if (10 <= length)
4 
5 while (bytes_received < bytes_expected)
6 //or
7 while (bytes_expected > bytes_received)
 1 //以前的慣例
 2 if (obj = NULL)   // 易產生bug
 3 if (NULL == obj) // 可以預防bug
 4 
 5 if (obj = NULL) // 現代編譯器會給出警告
 6 //test.cpp:185:11: 警告:建議在用作真值的賦值語句前後加上括號 [-Wparentheses]
7 // 185 | if (obj = NULL) 8 9 if ((obj = NULL)) // OK 10 if (obj == NULL) // OK

2. if / else 語句塊的順序

先處理正邏輯

 1 if (!url.HasQueryParameter("expand_all")) {
 2     response.Render(items);
 3 } else {
 4     for (int i = 0; i < items.size(); i++) {
 5         items[i].Expand();
 6     }
 7 }
 8
9 //當說“不要去想粉紅色的大象”時,不要就被“想粉紅色的大象”淹沒了 10 // 所以正向邏輯放在前面更易讀 11 if (url.HasQueryParameter("expand_all")) { 12 for (int i = 0; i < items.size(); i++) { 13 items[i].Expand(); 14 } 15 } else { 16 response.Render(items); 17 }

負邏輯更簡單/更危險/更有趣時,可以放在前面

1 if not file:
2 #    Log the error ...
3 else: 4 # ...

3. ?:表示式(又名“三目運算子”)

富有爭議的表示式

1 // 緊湊
2 time_str += (hour >= 12) ? "pm" : "am"; 
3 
4 // 冗長
5 if (hour >= 12) {
6     time_str += "pm";
7 } else {
8     time_str += "am";
9 }

然而這種表示式很有可能變得很難讀

1 return exponent >= 0 ? mantissa * (1 << exponent) : mantissa / (1 << -exponent);

要使理解的難度最小化,因此建議只在最簡單的情況下使用?:(“三目運算子”)

4. 避免使用do/while迴圈

do/while奇怪之處在於:條件放在其“保護”的程式碼之後。讀者需要讀兩遍程式碼,很不自然。

大多數do/while迴圈可以改成 while迴圈

1 //但是不要這樣做
2 body
3 while (condition) {
4     body (again)
5 }

5. 從函式提前返回

”保護語句“在函式開頭進行檢查

6. 臭名昭著的goto語句

大部分時候需要避免使用goto語句。但是下面的情況除外cleanup可以避免大段的重複程式碼

1 if (p == NULL) goto cleanup;
2 //...
3 cleanup:
4 fclose(file1);
5 fclose(file2);
6 //...
7 return;

7. 最小化巢狀

巢狀很深的程式碼很難理解。看上去很簡單的改動可能會使巢狀越來越深。

因此,當你對程式碼進行改動時,從全新的角度審視它,把它當成一個整體看待。

8. 通過提早返回來減少巢狀

9. 減少迴圈內巢狀,善用continue。

10. 你能理解執行的流程嗎?

執行緒 / 訊號量 / 中斷處理程式 / 異常 / 函式指標和匿名函式 / 虛方法

上面這些幕後執行的程式碼很有用,甚至可以讓程式碼冗餘更少,更具可讀性。

但是用的太多會令人難以理解,bug也更難跟蹤。不要讓程式碼中這些部分比例太高。

cleanup