不要使用裸露的If语句

120 阅读3分钟

不要使用裸露的if语句

对于C、PHP、Java和Javascript程序员来说,裸露的if语句是代码地雷。

Nick Galbreath-三月 23, 2018

对于许多基于C语法风格的编程语言来说,if语句的主体是由大括号限定的。

if (foo == 1) {
    delete_everything();
}

然而,在Javascript、Java、PHP、C和C++、Java、PHP中,允许 "裸 "if语句。这些语句只有一个主体,不使用大括号。

if (foo == 1) delete_everything();
if (foo == 1)
    delete_everything();

还有一些其他形式的裸语句,如裸for-loops,但这是最常见的。

有两个原因不能使用裸露的if语句。首先,它们会造成不理想的差异。第二,它们会引入危险的逻辑变化。

差异不友好

现代编程是一项团队运动,随着时间的推移,一个程序会通过一系列的小改动(diffs)而被改变。这些差异经常被扫描,并根据它们来决定是否进行全面审查。因此,我们真的希望拉动请求、提交和差异尽可能的小,尽可能的有针对性,没有很多噪音。通常情况下,if语句的主体需要扩展,或者需要添加调试。让我们看看赤裸裸的例子与之相比的差异。

if (foo == 1) {
    DEBUG("foo is 1)";
    delete_everything();
}

第一个结果是完全重写了这一行。

< if (foo == 1) delete_everything();
---
> if (foo == 1) {
>     DEBUG("foo is 1)";
>     delete_everything();
> }

第二种形式更糟糕,因为它的结果是更混乱的部分重写。

1c1,2
< if (foo == 1)
---
> if (foo == 1) {
>     DEBUG("foo is 1)";
2a4
> }

如果你使用正常的、多行的、带括号的格式,diff就变成了良性的。

>     DEBUG("foo is 1");

像这样的单一改动可能不是什么大问题,但往往会在许多地方增加调试。用赤裸裸的if语句,增加微不足道的调试语句,使简单的diff变成了多页的。

意外的逻辑变化

前面的例子假设程序员做了正确的事情,把一个裸露的if语句转换成有大括号的语句。但如果他们只是天真地添加了调试语句呢?

if (foo == 1)
    DEBUG("foo is 1)";
    delete_everything();

差异仍然很简单。

>     DEBUG("foo is 1");

但是逻辑却发生了巨大的变化,因为新的版本实际上是。

if (foo == 1)
    DEBUG("foo is 1)";
delete_everything();

oops。

这种情况也可以反过来发生,快速注释掉一行也会引发逻辑变化。

if (foo == 1)
//    delete_everything();
copy_files();

总结

如果你认为这是一个虚构的问题,我本人也被这个问题所困扰,其他人也有。阅读这个主题的stackexchange 线程,你几乎可以看到未来的事故正在等待发生,"如果别人搞砸了就不是我的问题 "的态度。

有趣的是,三个较新和最流行的语言golang、rust和swift都不允许裸露的if语句。他们产生的混乱的差异和不安全的逻辑变化无疑是其中的一些原因。如果你使用的是一种比较传统的语言,请在你的风格指南中禁止裸露的if语句,并加以执行。