18|控制结构:if的“快乐路径”原则
该思维导图由 AI 生成,仅供参考
Go 中的分支结构之认识 if 语句
- 深入了解
- 翻译
- 解释
- 总结
Go语言中的if语句是一种常用的分支控制结构,具有一些特点:代码块的左大括号与if关键字在同一行,布尔表达式不需要用括号包裹,且必须是布尔类型的值。文章介绍了多种形式的if语句,包括二分支结构和多分支结构。在多分支结构中,可以通过等价变换将其转换为层层缩进的二分支结构,便于理解和阅读。此外,文章还提到了操作符优先级的概念,并建议在布尔表达式中使用带有小括号的子布尔表达式,以提高代码的可读性和理解性。另外,文章介绍了if语句的“快乐路径”原则,即尽量使用单分支控制结构,使代码更易读、简洁、易维护。总的来说,通过本文的介绍,读者可以快速了解Go语言中if语句的特点和使用方法。文章还提出了一个思考题,引发读者对if语句中布尔表达式排列的思考。
《Tony Bai · Go 语言第一课》,新⼈⾸单¥59
全部留言(23)
- 最新
- 精选
- Darren如果加上“布尔表达式3在这段代码中实际被命中的机会更多,布尔表达式2次之,布尔表达式1最少”,这个条件,那么最优的性能最好的写法应该是最大概率的放到最前面,因此可以改成如下: func foo() { if boolean_expression3{ return } if boolean_expression2 { return } if boolean_expression1 { return } else代码 return } 那为什么命中的最多,写到前面,是最好的呢,这里面主要涉及到2个技术点:流水线技术和分支预测 流水线技术:简单的说,一条 CPU 指令的执行是由 取指令-指令译码-指令执行-结果回写组成的(简单的说哈,真实的流水线是更长更复杂的);第一条指令译码的时候,就可以去取第二条指令,因此可以通过流水线技术提高CPU的使用率。 分支预测:如果没有任何分支预测,那么就是按照程序的代码顺序执行,那么执行到if上一句的时候,指令译码就是if语句,取指令就是if语句块的第一句,那么if如果不满足的话,就会执行JMP指令,跳转到else,因此流水线中的取指令与指令译码其实是无用功。因此在没有任何分支预测优化的情况下,if语句需要把概率更高的条件写到最上面,更能体现流水线的威力。 但是现代计算机都有分支预测的优化,比如动态分支预测等技术,但是不管怎么说,把概率最大的放到最上面,还是很有必要的。 问题:在C语言中,有类似这样的宏定义,可以使用 __builtin_expect函数,主动提示那个分支的代码的概率更高,在go中是否也有类似的方法?还是说现在的编后端编译技术已经比较智能,不需要甚至禁止程序员手动指定分支预测了。 #define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0)
作者回复: 厉害!👍
2021-11-221266 - Darren可以改成这样子吧 func foo() { if boolean_expression1 { return } if boolean_expression2 { return } if boolean_expression3 { return } else代码 return }
作者回复: 改成快乐路径方式是ok的。 可能思考题没说清楚。这里说的“效果最好”,指的是这段代码的执行性能最好。 提示一下:如果从统计概率而言,布尔表达式3在这段代码中实际被命中的机会更多,布尔表达式2次之,布尔表达式1最少,那么排列应该如何变 化才能让这段代码执行性能最好呢?
2021-11-2228 - lesserror对于if的“快乐路径”原则深表认同,每次看见同事写的四五层以上的 if else 语句,有种“想死” 的冲动。 自以为逻辑能力很强,殊不知自己一时爽,后来者却无法维护这样的代码了。
作者回复: 是的。尽量写简洁易读的代码才是王道。
2021-11-234 - mikewoo依据被命中的概率,依次由高到低,把命中概率最高的放在最前面。
作者回复: 👍
2022-04-223 - Emptyfunc foo() { if boolean_expression1 { return } if boolean_expression2 { return } if boolean_expression3 { return } else代码 return } 从代码的可读性来讲应该写成这个样子,但是多个if条件的排列顺序要综合命中概率、条件判断复杂度、业务优先级等方面去考虑
作者回复: ✅
2022-02-193 - 🐎这个其他语言里一般叫做 early return(尽早返回)😁
作者回复: 👍
2022-09-05归属地:北京32 - qinsi还是之前的问题,happy path似乎让comma ok不再简洁 comma ok: ```go m := map[string]int { "v1": 1, "v2": 2, "v3": 3, } if v1, ok := m["v1"]; ok { if v2, ok := m["v2"]; ok { if v3, ok := m["v3"]; ok { fmt.Println(v1 + v2 + v3) } } } ``` happy path: ```go v1, ok := m["v1"] if !ok { return } v2, ok := m["v2"] if !ok { return } v3, ok := m["v3"] if !ok { return } fmt.Println(v1 + v2 + v3) ``` 换种写法也一样: ```go if _, ok := m["v1"]; !ok { return } v1 := m["v1"] if _, ok := m["v2"]; !ok { return } v2 := m["v2"] if _, ok := m["v3"]; !ok { return } v3 := m["v3"] fmt.Println(v1 + v2 + v3) ```
作者回复: 相对于第一个深层嵌套的“不易读”,下面虽然verbose一些,但代码一目了然啊。不知你是否有同样感觉。
2021-11-2252 - 子杨func main() { if a, c := f(), h(); a > 0 { println(a) } else if b := f(); b > 0 { println(a, b) } else { println(a, b, c) } } 这个例子是不是有点问题,为啥 f() 第一个 if 里赋值给了 a,第二个又赋值给了b。
作者回复: 这个只是为了演示“if语句的自用变量”的用法和作用域,不用太在意条件逻辑的合理性:)。
2023-03-29归属地:广东1 - Tristana假设每个表达式被命中概率为 boolean_expression1 > boolean_expression2 > boolean_expression3 , 可以将程序逻辑调整为命中率高的表达式放在最前面,命中后直接返回,调整后的逻辑如下 ``` func foo() { if boolean_expression1 { return 结果1 } if boolean_expression2 { return 结果2 } if boolean_expression3 { return 结果3 } return 结果5 } ```
作者回复: ✅
2022-06-101 - Forest使用switch case; func foo() { switch expression { case condition1: case condition2: case condition3: default: } }
作者回复: 可能思考题没说清楚。这里说的“效果最好”,指的是这段代码的执行性能最好。 提示一下:如果从统计概率而言,布尔表达式3在这段代码中实际被命中的机会更多,布尔表达式2次之,布尔表达式1最少,那么排列应该如何变化才能让这段代码执行性能最好呢? btw,使用switch-case,说明你基础很好。
2021-11-221