当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《为什么省略花括号被认为是一种不好的做法?》经验,为你挑选了28个好方法。

为什么每个人都告诉我编写这样的代码是一种不好的做法?

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();

问题:

    想要使用语言提供的更紧凑的语法是错误的吗?设计这些语言的人很聪明,我无法想象他们会提出一个总是不好用的功能.

    我们是否应该编写代码,以便最低的共同分母可以理解并且使用它没有任何问题?

    我还缺少另一个论点吗?

Zachary Yate.. 181

实际上,唯一真正让我感到困惑的是我在调试时,并注释掉了bar():

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

除此之外,我倾向于使用:

if(foo) bar();

这照顾上述情况.

编辑感谢您澄清问题,我同意,我们不应该将代码写入最低的共同标准.



1> Zachary Yate..:

实际上,唯一真正让我感到困惑的是我在调试时,并注释掉了bar():

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

除此之外,我倾向于使用:

if(foo) bar();

这照顾上述情况.

编辑感谢您澄清问题,我同意,我们不应该将代码写入最低的共同标准.


当然这很粗糙,但我认为维护者最大的问题是他们会添加第二行,并且没有意识到它不是条件语句的一部分,即使它看起来应该是这样.
我不喜欢一种衬里样式,因为我总是去寻找下面的循环体.
我觉得单行风格比有用更刺激,因为(特别是在深度嵌套 - 呃)声明可能很容易被重读,并且可能会引起混淆.我几乎专门使用这样的单语句ifs进行输入验证(即早期返回)或循环控制(例如忽略文件系统遍历中不相关的文件名),但是,空白行有助于将它们从主代码中设置出来.

2> CrashCodes..:

阅读速度......

除了已经提到的内容.在这一点上,我已经习惯于使用大括号和空格来解析if语句.所以我读到:

if (condition)
{
    DoSomething();
}

DoSomethingElse();

比我读的快一点:

if (condition) DoSomething();

DoSomethingElse();

如果它看起来像这样,我读得慢一点:

if (condition) DoSomething();
DoSomethingElse();

我读这个比以前慢得多:

if (condition) 
    DoSomething();
DoSomethingElse();

因为我不禁在案件中再次阅读,并想知道作者是否打算:

if (condition)
{
    DoSomething();
    DoSomethingElse();
}

已经涵盖了一般性,但在阅读下面的内容时,我会对此进行一段时间的研究以确定作者的意图.我甚至可能追捕原作者以确认.

if (condition) 
    DoSomething();
    DoSomethingElse();


问题解决了,在你的第四个样本中,你只是在if语句之后放一个空行从DoSomethingElse()中分离出来这就是我所做的和可读性几乎与第一个样本相同(如果不是更好;-P)另一件事是将线条分成2或3组可以显着提高可读性,只需更快地扫描代码即可.
无支撑式的问题让你浪费宝贵的注意力来思考块是否有括号而不是更重要的东西.仅凭这一点就足以使用最简单的约定,即总是大括号.
也许是因为我已经习惯了Python,但是将第一个大括号放在与if语句相同的行上可以让我更快地阅读+理解它.
大括号本质上是明确的.我会坚持的,谢谢.
在最后一个案例中,追捕原作者并打他... ...)

3> Adam Jaskiew..:

如果它是小的东西,写这样:

if(foo()) bar();

如果它足够长到分成两行,请使用大括号.


当然,但由于上下文是C#,这应该覆盖绝大多数用户......
但是,调试器不是很友好.你如何在"酒吧"部分设置断点?
@Nemanja:把光标放在bar()上; 然后点击F9.VS2005和VS2008都处理内部断点,如果它们是单独的"语句".
GalanticCowboy:环境比你知道的还要多.:-)

4> FredV..:

我也曾经认为最好只在真正需要时使用牙箍.但不是了,主要的原因是,当你有很多代码时,它确实使它更具可读性,你可以在拥有一致的支撑样式时更快地解析代码.

除了有人在if上添加第二个语句之外,总是使用大括号的另一个好理由是这样的事情会发生:

if(a)
   if(b)
     c();
else
   d();

您是否注意到else子句实际上是"if(b)"的子句?你可能做过,但是你会相信任何人都熟悉这个陷阱吗?

所以,如果只是为了保持一致性,并且因为你永远不知道当其他人(它总是其他人都是愚蠢的)改变代码时会发生什么意外的事情,我总是把括号,因为它使源代码更易读,更快解析你的脑.仅对于最简单的if语句,例如if如何进行委托或类似于switch,你知道该子句永远不会扩展,我会省略括号.


这是我使用大括号的两种情况之一.否则不是.
@ alexander.biskop:当然不是,因为这给了else块一个不同的含义(`!a ||!b`)比用(`!a`)或没有(`a &&!b`)添加括号.
这应该写成好像(a && b)......首先是一个方法.
@ alexander.biskop:同时,嵌套ifs的调试更容易,每个ifs都有更简单的条件,因为你可以单步进入每个.

5> tvanfosson..:

我更喜欢大括号提供的清晰度.你确切地知道是什么意思,不必猜测是否有人只是愚蠢而把它们关掉(并引入了一个bug).我省略它们的唯一一次是将if和action放在同一行上.我也不经常这样做.我实际上更喜欢通过将大括号放在自己的行上而引入的空白,尽管从多年的K&R C类编程开始,以大括号结束这一行是我必须努力克服的做法,如果IDE不强制执行它我.

if (condition) action();  // ok by me

if (condition) // normal/standard for me
{
   action();
}



6> Manuel Ceron..:

这并不总是被认为是一种不好的做法.在Mono项目编码准则建议不要使用大括号,如果它是没有必要的.同为GNU编码标准.我认为这与个人品味一样,与编码标准一样.


在阅读整个指南后,看一下Mono代码对我来说似乎很**.

7> Jayden..:

线很便宜.处理器功率很便宜.开发人员的时间非常昂贵.

作为一般规则,除非我正在开发一些绝对资源/速度关键的应用程序,否则我总是会错误地编写代码

(a)任何其他开发人员都可以轻松地遵循我正在做的事情

(b)评论可能需要它的代码的特定部分

(c)如果出现问题,易于调试

(d)如果将来需要易于修改(即添加/删除代码)

从业务角度来看,代码的速度或学术优雅是次要的.这并不是说我打算编写笨重或丑陋的代码,但这是我的优先顺序.

通过在大多数情况下省略花括号,对我来说使(b),(c)和(d)更难(注意不是不可能).我会说使用花括号是否对(a)没有影响.


你关于(a)的最后陈述是一种观点,即大量的开发者,包括其他海报,都会争辩.

8> Maghis..:

我认为这是您正在进行的项目和个人品味的指导方针.

我通常在不需要它们时省略它们,除了以下一些情况:

if (something)
    just one statement; // i find this ugly
else
{
    // many
    // lines
    // of code
}

我更喜欢

if (something)
{
    just one statement; // looks better:)
}
else
{
    // many
    // lines
    // of code
}



9> Torlack..:

可以咬你的一个例子是在C/C++宏的旧时代.我知道这是一个C#问题,但是编码标准通常会在没有创建标准的原因的情况下继续存在.

如果在创建宏时不是很小心,最终会导致if语句不使用{}.

#define BADLY_MADE_MACRO(x) function1(x); function2(x);

if (myCondition) BADLY_MADE_MACRO(myValue)

现在,不要误解我的意思,我不是说你应该总是这样做以避免在C/C++中出现这个问题,但是由于这个原因,我不得不处理一些非常奇怪的错误.


如果只有所有代码都声明自己......*叹气*

10> OscarRyz..:

我用同样的方式思考.

直到有一天(为什么总会有"一天"永远改变你的生活?)我们花了24到36个小时没有睡觉调试生产代码只发现有人没有把括号与搜索/替换变化相结合.

就是这样的.

 if( debugEnabled ) 
      println( "About to save 1 day of work to some very important place.");
 saveDayData();

之后发生了什么

 if( debugEnabled ) 
 //     println( "About to save 1 day of work to some very important place.");
 saveDayData();

事实证明,该系统每天产生500 MB的日志,我们被要求停止它.调试标志是不够的,所以搜索和替换println是有序的.

仍然当应用程序进入生产时,调试标志已关闭,并且从未调用过重要的"saveDayData".

编辑

现在我唯一不使用大括号的地方是if/try构造.

if( object != null ) try { 
     object.close();
} catch( .....

看完一位超级明星开发者之后.


我不明白.你有一个控制调试的变量(debugEnabled),你仍然使用注释来禁用调试??? 你为什么不把debugEnabled设置为false?

11> Ozzah..:

我很高兴:

foreach (Foo f in foos)
  foreach (Bar b in bars)
    if (f.Equals(b))
      return true;

return false;

就个人而言,我不明白为什么

foreach (Foo f in foos)
{
  foreach (Bar b in bars)
  {
    if (f.Equals(b))
    {
      return true;
    }
  }
}

return false;

更具可读性.

是的,行是免费的,但为什么我必须滚动浏览页面和代码页的大小一半?

如果可读性或可维护性存在差异,那么,确定,将括号放入...但在这种情况下我看不出任何理由.

另外,我总是把嵌套用于嵌套if if我嵌套else的地方

if (condition1)
  if (condition2)
    doSomething();
  else (condition2)
    doSomethingElse();

VS

if (condition1)
  if (condition2)
    doSomething();
else (condition2)
  doSomethingElse();

是非常令人困惑的,所以我总是把它写成:

if (condition1)
{
  if (condition2)
    doSomething();
  else (condition2)
    doSomethingElse();
}

只要可能,我使用三元运算符,但我从不 嵌套它们.



12> gman..:

坦率地说,我认为:

优秀的程序员在防守程序上编程,坏程序员则不然.

由于上面有几个例子和我自己类似的与遗忘大括号有关的错误的经历,所以我学会了总是坚持不懈的方法.

其他任何事情都是选择个人风格而不是安全,这显然是糟糕的编程.

乔尔甚至在" 使错误的代码看错"中提到了这一点

一旦你因为缺少括号而得到一个bug,你就会发现丢失的括号看起来是错误的,因为你知道它是另一个bug发生的可能的地方.



13> Tom Ritter..:

总有例外情况,但我认为只有在其中一种形式时才省略大括号:

if(x == y)
   for(/* loop */)
   {
      //200 lines
   }

//rampion's example:
for(/* loop */)
{
   for(/* loop */)
      for(/* loop */)
      {
         //several lines
      }
}

否则,我没有问题.


不好的例子.在这两种情况下,我都会将200行for循环纳入自己的方法,或者最好是几种方法.
@AdamJaskiewicz对.它确实发生了.我们必须考虑**会发生什么,而不是*应该*发生什么.如果我们可以限制自己应该*发生什么,我们就不用担心错误了.
没错,但它确实发生了.另外,每当一个块长于读者屏幕的时间很长时,你就会遇到这个问题.并且您无法控制代码阅读器的屏幕高度.他们可能只会在每一侧看到几条线.
它确实发生了.这并不意味着*应该*发生.

14> Jon Skeet..:

我偶尔使用最底层的代码(多个使用语句),但除此之外我总是把括号放进去.我发现它使代码更清晰.显而易见的是,不仅仅是缩进,语句是块的一部分(因此可能是if等的一部分).

我见过了

if (...)
    foo();
    bar();

臭虫咬我(或者更确切地说,"我和他的同事" -我其实没有引进的bug)一次.尽管我们当时的编码标准建议在任何地方使用括号.我花了很长时间才发现 - 因为你看到了你想要看到的东西.(这是大约10年前的事.也许我现在发现它更快.)

当然,如果你使用"支撑在行尾"它减少了额外的线路,但我个人不喜欢这种风格.(我在工作中使用它,发现它不如我预期的那么令人不愉快,但它仍然有点不愉快.)



15> chills42..:

我同意"如果你足够聪明,可以让某人付钱给你编写代码,那么你应该足够聪明,不要仅仅依靠缩进来查看代码的流程."

但是......可能会犯错误,而这一点很难调试......特别是如果你正在查看其他人的代码.



16> James McMaho..:

我的理念是,如果它使代码更具可读性,为什么不这样做呢?

显然你必须在某处绘制线条,比如在简洁和过于描述的变量名称之间找到快乐的媒介.但括号确实可以避免错误并提高代码的可读性.

你可以说,聪明到足以成为编码人员的人会变得足够聪明,以避免出现无括号语句的错误.但你真的可以说你从来没有像拼写错误这样简单的东西被绊倒吗?在看大型项目时,这样的细节可能会让人不知所措.


当然这是非常主观的.有时将它们关闭会提高可读性.

17> Jay Bazuzi..:

令我印象深刻的是,我在计算机编程领域的同行(你很多)并没有因为你在单行块上跳过括号时潜在错误的前景而感到沮丧.

我想这意味着我不聪明.我多次犯了这个错误.我调试了其他人的错误.因为这个问题,我已经看到了带有错误的软件(运行VS2002的机器的RDP和你的监视窗口字体会变得很糟糕).

如果我看看我所做的所有错误,可以通过改变编码风格来避免,列表很长.如果我在每种情况下都没有改变我的方法,我可能永远不会成为程序员.再说一遍,我想我不聪明.为了弥补这一点,我长期以来一直是单线模块上大括号的坚定用户.

也就是说,世界上有些事情发生了变化,使得"你在单线块上使用括号"的规则与摩西把它带到我们身上相比不那么重要:

一些流行的语言通过让计算机读取缩进来解决问题,就像程序员那样(例如Python).

我的编辑器会自动为我格式化,因此我通过缩进误导的可能性大大降低.

TDD意味着如果我引入一个bug,因为我被一个单行块搞糊涂了,我更有可能很快发现这个bug.

重构和语言表达意味着我的块更短,并且单行块的发生频率比使用时更频繁.假设有一个无情的ExtractMethod应用程序,我的整个程序中可能只有单行块.(我想知道那会是什么样的?)

实际上,在单行块上无情地重构和省略括号有一个明显的好处:当你看到大括号时,你脑海中会发出一个小小的警报,说"这里的复杂性!小心!".想象一下,如果这是常态:

if (condition) Foo();   // normal, everyday code

if (condition) 
{
    // something non-trivial hapening; pay attention!
    Foo();
    Bar();
}

我打算将我的编码约定更改为"单行块可能永远不会有大括号"或"如果你可以将块放在与条件相同的行上,并且它都适合80个字符,省略大括号".走着瞧.



18> 小智..:

在三个公约中:

if(addCurleyBraces()) bugFreeSofware.hooray();

和:

if(addCurleyBraces())
    bugFreeSofware.hooray();

和(表示使用开口和右括号的任何缩进样式):

if(addCurleyBraces()) {
    bugFreeSofware.hooray();
}

我更喜欢最后一个:

如果所有if语句都以统一的方式编写,我会发现它更容易阅读.

它可能使软件更健壮,无bug.然而,所有现代IDE和高级文本编辑器都有很好的自动缩进功能,我认为每个人都应该使用它,只要它不会弄乱注释格式或违反团队标准(在很多情况下,可以创建自定义格式设置并与团队分享).我的观点是,如果正确完成缩进,可以减少bug引入的风险.

我更喜欢将布尔表达式和语句执行到不同的行.我希望能够为调试目的标记一行.即使我正在使用IDE,我可以在其中标记语句并继续它,它是一个交互式操作,我可能忘记了我开始调试的地方,或者至少我需要花费更多的时间来完成代码的几个步骤时间(因为我必须在调试期间每次手动标记位置).



19> Paul Mitchel..:

反对使用大括号的主要论点是它们使用额外的行并且需要额外的缩进.

行(几乎)是免费的,最小化代码中的行数不应该是一个目标.

缩进与大括号的使用无关.在你的级联'使用'示例中,我仍然认为即使你省略大括号也应该缩进它们.



20> Christopher ..:

我非常相信编写简洁明了的代码,但我总是使用花括号.我发现它们是一种快速查看特定代码行存在范围的便捷方式.没有歧义,它只是明确地摆在你面前.

有些人可能会说这是偏好的情况,但我发现程序的逻辑流程如果内部一致则更容易遵循,而且我不认为编写这样的IF语句是一致的.

if(x < y)
    x = y;
else
    y = x;

而另一个像这样;

if(x < y)
{
    x = y;
    x++;
}
else
{
    y = x;
    y++;
}

我更喜欢选择一种一般风格并坚持下去:)



21> rampion..:

其中一个主要问题是,当你有一个船和非一个衬垫的区域,从控制statment分离(沿for,if,你有什么)和statment结束.

例如:

for (...)
{
  for (...)
    for (...) 
    {
      // a couple pages of code
    }
  // which for block is ending here?  A good text editor will tell you, 
  // but it's not obvious when you're reading the code
}


为什么你的for循环中有几页代码呢?
通常,这几页代码应该在一个单独的函数中.

22> Liggy..:

我曾经是"花括号是必须的!"的巨大支持者,但自从采用单元测试后,我发现我的单元测试保护了无括号语句,例如:

if (foo)
    snafu();
    bar();

通过良好的单元测试,我可以放心地省略大括号的简单语句以提高可读性(是的,这可能是主观的).

或者,对于类似上面的内容,我可能会将其看起来像:

if (foo) snafu();

这样,需要在条件中添加bar()的开发人员更容易识别缺少花括号,并添加它们.


我不会依靠单元测试来找到它.LINT也许,单元测试没有!
你说"我不需要它"然后给出了使用它的理由:可读性!
@Kristen - 单元测试的想法是断言方法的行为.如果行为发生变化(如上所述),单元测试将失败.我没有看到问题.

23> 小智..:

使用一些个人判断.

if (foo)
  bar();

很好.除非你真的担心傻瓜后来会这样做:

if (foo)
  bar();
  baz();

如果你不担心蠢货,你很好(我不是 - 如果他们不能正确获得基本的代码语法,这是他们最少的问题)>

作为交换,它更具可读性.

剩下的时间:

if (foo) {
  bar();
  baz();
}

只要我记得,这一直是我最喜欢的.另外:

if (foo) {
  bar();
  baz();
} else {
  qux();
}

适合我.

垂直空间本身并不十分相关,可读性也是如此.一条直线上的左括号只会停止语法元素的对话,直到你的眼睛向下移动到下一行.不是我喜欢的.



24> stone..:

好的,这是一个已经回答死亡的老问题.我有一些要补充的东西.

首先,我只想说使用支架.它们只能帮助提高可读性,并且可读性(对于您自己和他人!)应该在您的优先级列表中非常高,除非您正在编写程序集.总是无法读取的代码,总是会导致错误.如果你发现大括号会让你的代码占用太多空间,那么你的方法可能太长了.如果你做得对,大多数或所有方法都应该适合一个屏幕高度,而Find(F3)就是你的朋友.

现在我的补充:这有一个问题:

if (foo) bar();

尝试设置一个仅在bar()运行时才会被击中的断点.您可以通过将光标放在代码的后半部分来在C#中执行此操作,但这并不明显,并且有点痛苦.在C++中你完全不能这样做.我们处理C++代码的最高级开发人员之一坚持将'if'语句分成两行,因此.我同意他的看法.

这样做:

if (foo)
{
    bar(); //It is easy to put a breakpoint here, and that is useful.
}


右键单击栏并选择Insert Breakpoint ...根本不难.了解你的工具.

25> Elie..:

假设你有一些代码:

if (foo)
    bar();

然后其他人出现并添加:

if (foo)
    snafu();
    bar();

根据它的写法,bar(); 现在无条件执行.通过包含花括号,可以防止出现这种意外错误.编写代码的方式应该是难以或不可能犯这样的错误.如果我正在进行代码审查并看到缺少​​的大括号,特别是分布在多行中,我会创建一个缺陷.在合理的情况下,将其保持在一行,以便将出现这种错误的可能性再次保持在最低限度.



26> Nathan Prath..:

为了防止代码占用大量空间,我使用了Code Complete中推荐的技术:

if (...) {
    foo();
    bar();
}
else {
    ...
}


这通常被称为K&R风格.基于Kernighan和Ritchie的书"C编程语言":http://en.wikipedia.org/wiki/The_C_Programming_Language_(book).并且它不应该让你改变.

27> plinth..:

减少线条并不是放弃括号的好理由.如果您的方法太大,它可能应该重构为较小的部分或重组.这样做无疑会提高可读性,而不仅仅是取出括号.



28> Marc Charbon..:

我总是在适当时省略它们,例如在你的第一个例子中.清晰,简洁的代码我可以通过浏览来查看和理解,比我必须逐行滚动和逐行读取的代码更容易维护,调试和理解.我想大多数程序员都同意这一点.

如果你开始做多个嵌套,if/else子句等等,它很容易失控,但我认为大多数程序员应该能够知道绘制线的位置.

我觉得这有点像if ( foo == 0 )vs 的论点if ( 0 == foo ).后者可以防止新程序员的错误(甚至可能偶尔为退伍军人),而前者在维护代码时更容易快速阅读和理解.

推荐阅读
wangtao
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有