17

作为我不久前写的代码标准文档的一部分,我强制要求“您必须始终为循环和/或条件代码块使用大括号,即使(尤其是)它们只有一行。”

例子:

// this is wrong
if (foo) 
    //bar
else 
    //baz
while (stuff)
    //things

// This is right.
if (foo) {
    // bar
} else {
    // baz
}
while (things) {
    // stuff
}

如果你不支持单行,然后有人评论它,你就有麻烦了。如果你不支持单行,并且缩进在其他人的机器上显示不一样......你有麻烦了。

所以,问题:有充分的理由说明这将是一个错误的或不合理的标准吗?对此进行了一些讨论,但没有人能提供比“感觉难看”更好的反驳。

4

21 回答 21

23

我能提供的最好的反驳论点是,空间占用的额外行减少了您一次可以看到的代码量,而您一次可以看到的代码量是决定容易程度的一个重要因素就是发现错误。我同意你给出的包含大括号的原因,但是在多年的 C++ 中,我只能想到一个结果是我犯了一个错误,而且那是我没有充分理由跳过大括号的地方反正。不幸的是,我无法告诉您是否看到这些额外的代码行在实践中是否有帮助。

我可能更有偏见,因为我喜欢在相同缩进级别匹配大括号的对称性(以及将包含的语句隐含分组为一个执行块) - 这意味着始终添加大括号会增加很多行项目。

于 2009-12-16T18:39:41.877 回答
22

我在一定程度上强制执行这一点,除了评估为返回或继续循环的 if 语句的小例外。

所以,按照我的标准,这是正确的:

if(true) continue;

就像这个

if(true) return;

但规则是,要么返回,要么继续,而且都在同一行。否则,为一切做好准备。

推理既是为了有一个标准的方法,也是为了避免你提到的评论问题。

于 2009-12-16T18:17:29.430 回答
12

我认为这条规则有点矫枉过正。严苛的标准不会造就优秀的程序员,它们只会降低一个懒汉搞砸的可能性。

您提供的示例是有效的,但它们比强制大括号有更好的解决方案:

如果你不支持单行,然后有人评论它,你就有麻烦了。

两种做法可以更好地解决这个问题,选择一种:

1)用单行注释掉单行前的if,等。while即对待

if(foo)
    bar();

像任何其他多行语句(例​​如,多行赋值,或多行函数调用):

//if(foo)
//    bar();

//2)用 a前缀;

if(foo)
;//    bar();

如果你不支持单行,并且缩进在其他人的机器上显示不一样......你有麻烦了。

不你不是; 代码的工作原理相同,但更难阅读。修正你的缩进。选择制表符或空格并坚持使用它们。 不要混合使用制表符和空格进行缩进。 许多文本编辑器会自动为您解决此问题。

写一些 Python 代码。这将至少解决一些不良的缩进习惯。

此外,} else {在我看来,类似 TIE 战斗机的网络黑客版本的结构。

是否有充分的理由说明这将是一个错误或不合理的标准?对此进行了一些讨论,但没有人能提供比“感觉难看”更好的反驳。

多余的大括号(和括号)是视觉上的混乱。视觉混乱使代码更难阅读。代码越难阅读,就越容易隐藏错误。

int x = 0;
while(x < 10);
{
    printf("Count: %d\n", ++x);
}

强制大括号无助于找到上述代码中的错误。

PS我是“每条规则都应该说明原因”学校的订阅者,或者正如达赖喇嘛所说,“知道规则,这样你就可以正确地打破它们。”

于 2009-12-16T19:35:20.397 回答
8

我还没有让任何人想出一个不总是使用花括号的充分理由。

好处远远超过了我听到的任何“感觉难看”的理由。

存在编码标准以使代码更易于阅读并减少错误。

这是一个真正有回报的标准。

于 2009-12-16T18:17:39.337 回答
5

我发现很难与减少错误并使代码更具可读性的编码标准争论。起初对某些人来说可能会觉得难看,但我认为这是一个完全有效的实施规则。

于 2009-12-16T18:18:48.367 回答
5

我站在大括号应该根据压痕匹配的基础上。

// This is right.
if (foo) 
{
    // bar
}
else 
{
    // baz
}

while (things) 
{
    // stuff
}

至于您的两个示例,我认为您的示例的可读性略低,因为找到匹配的右括号可能很难,但在缩进不正确的情况下更具可读性,同时允许更容易地插入逻辑。这不是一个巨大的差异。

即使缩进不正确,if 语句也会执行下一条命令,不管它是否在下一行。不将两个命令放在同一行的唯一原因是调试器支持。

于 2009-12-16T18:24:16.980 回答
4

我看到的一大优势是更容易将更多语句添加到大括号的条件和循环中,并且在开始时创建大括号不需要很多额外的击键。

于 2009-12-16T18:19:09.860 回答
4

我个人的规则是,如果它是一个非常短的“如果”,则将其全部放在一行上:

if(!something) doSomethingElse();

一般来说,我只有在连续有一堆这样的 if 时才使用它。

if(something == a) doSomething(a);
if(something == b) doSomething(b);
if(something == b) doSomething(c);

不过这种情况并不经常出现,所以否则,我总是使用大括号。

于 2009-12-16T18:25:20.273 回答
4

目前,我和一个按照这个标准生活的团队一起工作,虽然我很抗拒它,但我为了统一而遵守。

我反对禁止使用异常或模板或宏的团队的原因与我反对的原因相同:如果您选择使用一种语言,请使用整个语言。如果大括号在 C 和 C++ 以及 Java 中是可选的,那么按照惯例强制使用它们会显示出对语言本身的一些恐惧。

我了解此处其他答案中描述的危险,并且我了解对统一性的渴望,但我不同情语言子集,除非有一些严格的技术原因,例如某些环境的唯一编译器不适应模板,或与 C 代码交互排除广泛使用例外。

我一天的大部分时间都在审查初级程序员提交的更改,而出现的常见问题与大括号放置或语句在错误位置结束无关。危险被夸大了。我宁愿把时间花在更多的实质性问题上,而不是寻找编译器乐意接受的违规行为。

于 2009-12-16T19:59:46.650 回答
4

一组程序员能够很好地遵循编码标准的唯一方法是将规则的数量保持在最低限度。

平衡收益与成本(每条额外的规则都会让程序员感到困惑和困惑,并且在达到一定阈值之后,实际上会降低程序员遵循任何规则的机会)

所以,要制定一个编码标准:

  • 确保您可以用明确的证据证明每条规则都比其他规则更好。

  • 看看规则的替代方案——真的需要吗?如果您的所有程序员都很好地使用了空格(空白行和缩进),那么 if 语句很容易阅读,并且即使是新手程序员也无法将“if”中的语句误认为是独立的语句。如果你遇到很多与 if 作用域相关的错误,那么根本原因可能是你的白色/缩进风格很差,这使得代码不必要地难以阅读。

  • 通过它们对代码质量的可衡量影响来确定您的规则的优先级。通过强制执行规则可以避免多少错误(例如“始终检查 null”、“始终使用断言验证参数”、“始终编写单元测试”与“即使不需要也始终添加一些大括号”) . 以前的规则每年将为您节省数千个错误。大括号规则可能会为您节省一个。也许。

  • 保持最有效的规则,并丢弃谷壳。谷壳至少是比忽略规则可能发生的任何错误都花费您更多实施成本的任何规则。但很可能如果你有超过 30 条左右的关键规则,你的程序员会忽略其中的许多,你的好心也会化为乌有。

  • 解雇任何注释掉随机代码而不阅读它的程序员:-)

PS我对大括号的立场是:如果“if”语句或其内容都是单行,那么你可以省略大括号。这意味着如果您有一个包含单行注释和单行代码的 if,则内容需要两行,因此需要大括号。如果 if 条件跨越两行(即使内容是单行),那么您需要大括号。这意味着您只在琐碎、简单、易于阅读的情况下省略大括号,在实践中从未犯过错误。(当语句为空时,我不使用大括号,但我总是在注释中明确说明它是空的,并且是故意的。但这与另一个主题接壤:在代码中显式以便读者知道你的意思一个范围是空的,而不是电话响了,你忘了完成代码)

于 2009-12-16T21:20:04.943 回答
3

许多语言都有这样的语法(我特别想到 perl)来处理这种“丑陋”。所以像:

if (foo)     
//bar
else     
//baz

可以使用三元运算符写成三元:

foo ? bar : baz

while (something is true)
{
blah 
}

可以写成:

blah while(something is true)

然而,在没有这种“糖”的语言中,我肯定会包括大括号。就像您说的那样,它可以防止不必要的错误潜入并使程序员的意图更加清晰。

于 2009-12-16T18:26:03.627 回答
3

我并不是说这是不合理的,但在 15 年多的使用类 C 语言编码的过程中,我没有遇到过省略大括号的问题。注释掉一个分支在理论上听起来像是一个真正的问题——我只是从未见过它在实践中发生过。

于 2009-12-16T18:34:02.840 回答
3

始终使用大括号的另一个优点是它使搜索和替换以及类似的自动化操作更容易。

例如:假设我注意到它functionB通常在 之后立即调用functionA,并且具有类似的参数模式,因此我想将重复的代码重构为新的combined_function. 如果您没有足够强大的重构工具 ( ^\s+functionA.*?;\n\s+functionB.*?;),正则表达式可以轻松处理这种重构,但是如果没有大括号,简单的正则表达式方法可能会失败:

if (x)
  functionA(x);
else
  functionA(y);
functionB();

会成为

if (x)
  functionA(x);
else
  combined_function(y);

在这种特殊情况下,更复杂的正则表达式会起作用,但我发现能够使用基于正则表达式的搜索和替换、一次性 Perl 脚本和类似的自动代码维护非常方便,所以我更喜欢编码风格这不会使那变得不必要的复杂。

于 2009-12-16T20:04:40.057 回答
3

我不赞成你的论点。就个人而言,我不知道有谁曾经“不小心”在if. 我会理解说嵌套 if语句应该有大括号以避免悬挂其他,但是正如我所看到的,由于担心 IMO 放错了位置,您正在强制执行一种样式。

于 2009-12-16T20:06:23.080 回答
1

这是我遵循的不成文(直到现在我想)规则。我相信它在不牺牲正确性的情况下提供了可读性。它基于这样一种信念,即在很多情况下,短格式比长格式更具可读性。

  • 如果语句的任何if/else if/else多于一行,请始终使用大括号。评论计数,这意味着条件中任何位置的评论意味着条件的所有部分都得到大括号。
  • 当语句的所有块正好是一行时,可以选择使用大括号。
  • 切勿将条件语句与条件放在同一行。if 语句后面的行总是有条件地执行。
  • 如果条件语句本身执行必要的操作,则形式将是:

    for (init; term; totalCount++)
    {
        // Intentionally left blank
    }
    

当您只需说出以下内容时,无需以冗长的方式对其进行标准化:

永远不要以牺牲可读性为代价留下大括号。如有疑问,请选择使用大括号。

于 2009-12-16T18:42:29.733 回答
1

我认为大括号的重要之处在于它们非常明确地表达了程序员的意图。您不必从缩进中推断出意图。

也就是说,我喜欢 Gus 建议的单线返回并继续。意图很明显,而且更清晰,更易于阅读。

于 2009-12-16T18:43:41.280 回答
1

如果您有时间阅读所有这些内容,那么您就有时间添加额外的大括号。

于 2009-12-16T20:49:18.843 回答
0

为了可维护性,我更喜欢在单行条件句中添加大括号,但我可以看到没有大括号的情况看起来更干净。它不会打扰我,但有些人可能会被额外的视觉噪音关闭。

我也无法提供更好的反驳。对不起!;)

于 2009-12-16T18:18:13.923 回答
0

根据语言的不同,单行条件语句或循环语句的大括号不是强制性的。事实上,我会删除它们以减少代码行数。

C++:

版本 1:

class InvalidOperation{};

//...
Divide(10, 0);
//...
Divide(int a, in b)
{
   if(b == 0 ) throw InvalidOperation();
   return a/b;
}

版本 2:

class InvalidOperation{};

//...
Divide(10, 0);
//...
Divide(int a, in b)
{
   if(b == 0 )
   { 
      throw InvalidOperation();
   }
   return a/b;
}

C#:

版本 1:

foreach(string s in myList)
   Console.WriteLine(s);

版本2:

foreach(string s in myList)
{
   Console.WriteLine(s);
}

根据您的观点,版本 1 或版本 2 将更具可读性。答案是相当主观的。

于 2009-12-16T18:18:34.467 回答
0

对于这样的事情,我建议为您的 IDE 自动格式化程序提供一个配置模板。然后,每当您的用户按 alt-shift-F(或您选择的 IDE 中的任何按键)时,都会自动添加大括号。然后对大家说:“继续改变你的字体颜色、PMD 设置或其他任何东西。但请不要更改缩进或自动大括号规则。”

这利用了我们可用的工具来避免争论那些真的不值得通常花费在它上面的氧气。

于 2009-12-16T18:24:20.737 回答
0

哇。没有人知道悬空的 else 问题?这本质上是总是使用大括号原因。

简而言之,else 语句可能会产生令人讨厌的模棱两可的逻辑,尤其是在它们嵌套时。不同的编译器以自己的方式解决歧义。如果您不知道自己在做什么,那么放弃牙套可能是一个大问题。

美学和可读性无关。

于 2009-12-16T19:53:16.457 回答