《编写可读代码的艺术》第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也更难跟踪。不要让代码中这些部分比例太高。

原文地址:https://www.cnblogs.com/yyqng/p/14227526.html