为什么省略花括号被认为是一种不好的做法?

188

为什么每个人都告诉我像这样编写代码是一种不良实践呢?

if (foo)
    Bar();

//or

for(int i = 0 i < count; i++)
    Bar(i);

我认为省略花括号的最大优点是,有时候使用花括号会造成代码行数翻倍。例如,下面是用C#绘制标签发光效果的一些代码:

using (Brush br = new SolidBrush(Color.FromArgb(15, GlowColor)))
{
    for (int x = 0; x <= GlowAmount; x++)
    {
        for (int y = 0; y <= GlowAmount; y++)
        {
            g.DrawString(Text, this.Font, br, new Point(IconOffset + x, y));
        }
     }
 }
 //versus
using (Brush br = new SolidBrush(Color.FromArgb(15, GlowColor)))
    for (int x = 0; x <= GlowAmount; x++)
        for (int y = 0; y <= GlowAmount; y++)
            g.DrawString(Text, this.Font, br, new Point(IconOffset + x, y));

您还可以获得链接 usings 的附加好处,而无需缩进数百万次。

using (Graphics g = Graphics.FromImage(bmp))
{
    using (Brush brush = new SolidBrush(backgroundColor))
    {
        using (Pen pen = new Pen(Color.FromArgb(penColor)))
        {
            //do lots of work
        }
    }
 }
//versus
using (Graphics g = Graphics.FromImage(bmp))
using (Brush brush = new SolidBrush(backgroundColor))
using (Pen pen = new Pen(Color.FromArgb(penColor)))
{
    //do lots of work
}

花括号最常见的使用是为了维护编程,并避免在原始if语句和其预期结果之间插入代码带来的问题:

if (foo)
    Bar();
    Biz();

问题:

  1. 想使用语言提供的更紧凑的语法有错吗?设计这些语言的人很聪明,我无法想象他们会加入一种总是不好使用的特性。
  2. 我们应该还是不应该编写代码让最低公共分母能够理解并且没有问题地与之工作?
  3. 还有其他的论点我错过了吗?

8
我同意你的看法。省略它们。句号。 - Andrei Rînea
77
谁会在2010年关心某个东西有多少行啊?现在的显示器都很宽、很便宜,而且分辨率很高!我的显示器是2048 x 1152,而且我有两个!可读性比节省2个垂直线更重要,因为你很容易引入难以发现的细微错误。 - user177800
56
显示器宽而便宜,但不高也不便宜。垂直空间比水平空间更为紧缺。 - Adam Ruth
38
把它们横过来 :) - Zachary Yates
17
为了避免像苹果在2014年2月发现的SSL漏洞那样出糗,哈哈。 - learnvst
显示剩余15条评论
52个回答

0
每当我看到“这种风格可以节省空间”时,我总是感到困惑。
由于我很少甚至从不打印代码,所以对我来说,节省空间并没有明显的优势:在磁盘上节省一些字节并不值得,而且我也不会为屏幕上占用的空间付费。
有些人认为紧凑的代码更易读,我不会对此争论(高度主观),但作为业余艺术家和排版师,我非常重视空白使用...
我不会重复上述论点,但我会补充一点,那就是一致性:我不喜欢像下面这样的代码。
if (foo)
{
  // Lot of code
}
else
  DoStuff();

话虽如此,有时我会沉迷于不使用大括号的编程方式:在守卫条件中,当我需要提前退出时。

if (somethingBadHappened)
  return;

总之,我认为在重要的代码周围(几乎)系统地添加大括号可以提高可读性(代码“呼吸”,不会过于拥挤),一致性,并且可能避免一些愚蠢的错误(是的,这种错误很明显,但编码人员是人类(通常情况下),可能会感到疲劳、新手、压力大等)。

我已经为SciTE制作了一个Lua宏,可以通过一次按键和正确的缩进将这些大括号添加到任何代码块或当前行中:对我来说真的没有成本。

现在,如果您选择省略这些大括号,我不会起诉您。正如其他人指出的那样,其中一种选项可以在编码规则中设置。每个人都有自己的选择。


2
我不会为屏幕上占用的空间付费。但是,由于无法同时查看其他代码,您确实会因此付出代价。 - recursive

0
一方面,对于单个语句,我会省略大括号。另一方面,我会使用PC-Lint(http://www.gimpel.com/)检查所有的C代码,如果if()语句后面有两行或更多缩进的代码,它会标记为“可疑缩进”。
顺便说一下,将单个语句放在与if()同一行看起来是一个不错的主意。

0

我也喜欢更紧凑的格式。这就是为什么我经常在Visual Studio中按Ctrl+K,Ctrl+D重新格式化。我只希望每次按键后它都能自动为我完成。


0
另一方面,如果您为了节省行数而删除/不使用大括号,则需要重构代码。

0
如果你觉得“有时候”加上大括号会更有用,那么你应该始终保持一致性并添加大括号。 程序应该被编写成为人们阅读而非计算机。 我喜欢这样的大括号:
if (mybool)
{
  doMyStuff();
}
else
{
  doMyOtherStuff();
  checkStuff();
}

而不是像这样

if (mybool) {
  doMyStuff();
}
else {
  doMyOtherStuff();
  checkStuff();
}

而不是像这样

   if (mybool)
     doMyStuff(); 
   else 
   {  
     doMyOtherStuff();
     checkStuff(); 
   }

1
我更喜欢你的第二个例子。对我来说,这与特定的花括号字符是否匹配不太相关,而是关于一个概念性的起始-结束匹配的事情。 - Wick

0

好的,对我来说,这似乎更多是个人偏好。然而,我注意到为了可读性,最好有 { } 而不是没有。我注意到使用 ReSharper 时,ReSharper 倾向于删除它们,并且大多数 if 语句都像这样

if(this == yes)
      DoSomething();

但出于可读性的考虑,我总是这样做。

if(this == yes)
{
 DoSomething();
}

虽然在“if”语句中只有一行代码,可读性并没有太大的区别,但如果您将20-30行代码放入一个if语句中,则使用{}更容易阅读,并且可以减少代码中的错误和漏洞。


0

我通常使用花括号,除非内部最里层的语句是单行语句。因此,我的代码看起来像这样:

for (int i=0; i<10; i++) 
{
    for (int x=0; x<20; x++) 
    {
        if (someBoolValue)
            DoThis(x,y);
    }
}

另一个例外当然是使用堆叠的using语句。
毫无意义的写法。
using (Stream x = File.Open(...)) 
{
    using (Stream y = File.Create(...)) 
    {
        ...
    }
}

当你能够编写代码时

using (Stream x = File.Open(...))
using (Stream y = File.Create(...)) 
{
    ....
}

0

保罗说:

缩进与大括号的使用是独立的。

但在某些编码风格中并非如此。在我工作的地方,公司的编码标准允许我们在不严格需要时省略大括号;然而,编码标准要求我们对大括号以及其中的内容进行缩进,因此最终会得到类似于这样的代码:

if (something)
  {
    for (i = 0; i < count; i++)
      {
        foo();
      }
  }

如果没有花括号,这会变成:

if (something
  for (i = 0; i < count; i++)
    foo();

使用这种编码风格时,当嵌套深度较大,加上变量和函数名很长,并且总是使用大括号时,你要么会看到很多代码超出屏幕右侧,要么会有很多行换行,这两种情况都会使代码阅读或调试起来非常麻烦。因此,我总是尽可能地省略大括号。

至于将单个语句放在与 if 相同的行上,一些公司的编码标准(包括我们自己的)禁止这样做,因此这并不总是一个选项。

如果由我来选择,我会更改公司的编码标准,使大括号与 if、for 等级别相同,并将主体中的第一行(或注释)与开放大括号放在同一行上,如下所示:

if (something)
{ for (i = 0; i < count; i++)
  { foo();
  }
}

如果每对花括号只会增加一行额外的代码而不需要缩进,那么我更愿意(并且更有可能)总是使用花括号(甚至会支持“总是使用花括号”规则)。


-1

在大多数情况下,我更喜欢使用花括号。通常你会回到代码中添加更多的代码行,而你无论如何都必须添加它们。


-1
你有没有想过探索单行if else语句的这个选项:
(!a) ? Foo() : Bar();

8
有些人认为这是不雅的,因为三元运算符旨在计算值,而你例子中的流程控制则是一种副作用。 - recursive
@recursive - 你是对的。看起来使用这个计算值的常见做法是:http://en.wikipedia.org/wiki/%3F: - Michael Kniskern

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接