写直观的代码
最后更新于:2022-04-01 05:22:24
我写代码有一条重要的原则:如果有更加直接,更加清晰的写法,就选择它,即使它看起来更长,更笨,也一样选择它。比如,Unix命令行有一种“巧妙”的写法是这样:
~~~
command1 && command2 && command3
~~~
由于Shell语言的逻辑操作`a && b`具有“短路”的特性,如果`a`等于false,那么`b`就没必要执行了。这就是为什么当command1成功,才会执行command2,当command2成功,才会执行command3。同样,
~~~
command1 || command2 || command3
~~~
操作符`||`也有类似的特性。上面这个命令行,如果command1成功,那么command2和command3都不会被执行。如果command1失败,command2成功,那么command3就不会被执行。
这比起用if语句来判断失败,似乎更加巧妙和简洁,所以有人就借鉴了这种方式,在程序的代码里也使用这种方式。比如他们可能会写这样的代码:
~~~
if (action1() || action2() && action3()) {
...
}
~~~
你看得出来这代码是想干什么吗?action2和action3什么条件下执行,什么条件下不执行?也许稍微想一下,你知道它在干什么:“如果action1失败了,执行action2,如果action2成功了,执行action3”。然而那种语义,并不是直接的“映射”在这代码上面的。比如“失败”这个词,对应了代码里的哪一个字呢?你找不出来,因为它包含在了`||`的语义里面,你需要知道`||`的短路特性,以及逻辑或的语义才能知道这里面在说“如果action1失败……”。每一次看到这行代码,你都需要思考一下,这样积累起来的负荷,就会让人很累。
其实,这种写法是滥用了逻辑操作`&&`和`||`的短路特性。这两个操作符可能不执行右边的表达式,原因是为了机器的执行效率,而不是为了给人提供这种“巧妙”的用法。这两个操作符的本意,只是作为逻辑操作,它们并不是拿来给你代替if语句的。也就是说,它们只是碰巧可以达到某些if语句的效果,但你不应该因此就用它来代替if语句。如果你这样做了,就会让代码晦涩难懂。
上面的代码写成笨一点的办法,就会清晰很多:
~~~
if (!action1()) {
if (action2()) {
action3();
}
}
~~~
这里我很明显的看出这代码在说什么,想都不用想:如果action1()失败了,那么执行action2(),如果action2()成功了,执行action3()。你发现这里面的一一对应关系吗?`if`=如果,`!`=失败,…… 你不需要利用逻辑学知识,就知道它在说什么。