为什么每个人都告诉我编写这样的代码是一种不好的做法?
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();
问题:
-
想要使用语言提供的更紧凑的语法是错误的吗?设计这些语言的人很聪明,我无法想象他们会提出一个总是不好用的功能 .
-
我们是否应该编写代码,以便最低的共同分母可以理解并且使用它没有任何问题?
-
我还缺少另一个论点吗?
30 回答
实际上,唯一真正让我感到困惑的是我在调试时,并注释掉了bar():
除此之外,我倾向于使用:
这照顾上述情况 .
EDIT 感谢您澄清问题,我同意,我们不应该将代码编写到最低的共同标准 .
Speed of reading...
除了已经提到的内容 . 此时,我已经习惯于使用大括号和空格来解析if语句 . 所以我读到:
比我读的快一点:
如果它看起来像这样,我读得慢一点:
我读这个比以前慢得多:
因为我不禁在案件中再次阅读,并想知道作者是否打算:
已经涵盖了一般情况,但是当涉及到 reading 时,我将会对此进行一段时间的研究以确定作者的意图 . 我甚至可能追捕原作者确认 .
如果它是小的东西,写这样:
如果它足够长,可以分成两行,请使用大括号 .
我也曾经认为最好只在真正需要时使用牙箍 . 但现在不是了,主要原因是,当你拥有大量代码时,它确实使它更具可读性,并且当你拥有一致的支撑样式时,你可以更快地解析代码 .
除了有人在if中添加第二个语句之外,总是使用大括号的另一个好理由是这样的事情会发生:
您是否注意到else子句实际上是“if(b)”的子句?你可能做过,但是你会相信任何人都熟悉这个陷阱吗?
所以,如果只是为了保持一致性,并且因为你永远不知道当其他人(总是其他人都是愚蠢的)改变代码时会发生什么意外的事情,我总是把括号,因为它使源代码更易读,更快解析你的脑 . 仅对于最简单的if语句,例如if如何进行委托或类似于switch,你知道该子句永远不会被扩展,我会省略括号 .
我更喜欢大括号提供的清晰度 . 你确切地知道它的意思是什么,并且不必猜测是否有人只是愚弄并将它们抛弃(并引入了一个bug) . 我省略它们的唯一一次是将if和action放在同一行上 . 我也不经常这样做 . 我实际上更喜欢通过将花括号放在自己的行上而引入的空白,尽管从多年的K&R C类编程开始,用括号结束这一行是我必须努力克服的做法,如果IDE不强制执行它我 .
这并不总是被认为是一种不好的做法 . 如果没有必要,Mono Project Coding Guidelines建议不要使用花括号 . GNU Coding Standards也一样 . 我认为这与个人品味一样,与编码标准一样 .
线很便宜 . 处理器功率很便宜 . 开发人员的时间非常昂贵 .
作为一般规则,除非我正在开发一些绝对资源/速度关键的应用程序,否则我总是在编写代码时犯错
(a)任何其他开发人员都可以轻松地遵循我正在做的事情
(b)评论可能需要它的代码的特定部分
(c)如果出现问题,易于调试
(d)如果将来需要易于修改(即添加/删除代码)
从业务角度来看,代码的速度或学术优雅是次要的 . 这并不是说我开始编写笨重或丑陋的代码,但这是我的优先顺序 .
通过在大多数情况下省略花括号,对我来说使(b),(c)和(d)更难(注意不是不可能) . 我会说使用花括号是否对(a)没有影响 .
我认为这是您正在进行的项目和个人品味的指导方针 .
我通常在不需要它们时省略它们,除了有些情况如下:
我更喜欢
可以咬你的一个例子是在C / C宏的旧时代 . 我知道这是一个C#问题,但是编码标准通常会延续,而没有创建标准的原因 .
如果在创建宏时不是很小心,最终会导致if语句不使用{} .
现在,不要误解我的意思,我并不是说你应该总是这样做以避免在C / C中出现这个问题,但是由于这个原因我不得不处理一些非常奇怪的错误 .
我用同样的方式思考 .
直到有一天(为什么总会有“一天”永远改变你的生活?)我们花了24-36小时直接无需睡眠调试 生产环境 代码只发现有人没有把括号与搜索/替换变化相结合 .
就是这样的 .
之后发生了什么
事实证明,该系统每天产生500 MB的日志,我们被要求停止它 . 调试标志是不够的,所以搜索和替换println是有序的 .
仍然当应用程序进入 生产环境 时,调试标志已关闭,并且从未调用重要的“saveDayData” .
EDIT
现在我唯一不使用大括号的地方是if / try构造 .
看完一位超级明星开发者之后 .
坦率地说,我认为:
优秀的程序员在防守程序上编程,糟糕的程序员则不然 .
由于上面有几个例子和我自己类似的与忘记括号相关的错误的经历,所以我学会了总是坚持不懈的努力 .
其他任何事情都是选择个人风格而不是安全,这显然是糟糕的编程 .
乔尔甚至在Making Wrong Code Look Wrong中提到了这一点
一旦你因为缺少括号而得到一个bug,你会发现缺少的括号看起来是错误的,因为你知道它是另一个bug发生的潜在地方 .
我很高兴:
就个人而言,我不明白为什么
更具可读性 .
是的,行是免费的,但为什么我必须滚动浏览页面和代码页的大小一半?
如果可读性或可维护性存在差异,那么,确定,将括号放入......但在这种情况下,我认为没有任何理由 .
此外,如果's where I have nested else',我将始终为嵌套括号
VS
是非常令人困惑的,所以我总是把它写成:
只要可能,我使用三元运算符,但我从来没有nest them .
我同意“如果你足够聪明,可以让别人付钱给你编写代码,那么你应该足够聪明,不要仅仅依靠缩进来查看代码的流程 . ”
但是......可以犯错误,而这个错误很难调试......特别是如果你正在查看其他人的代码 .
我的理念是,如果它使代码更具可读性,为什么不这样做呢?
显然你必须在某处绘制线条,比如在简洁和过于描述的变量名称之间找到快乐的媒介 . 但括号确实可以避免错误并提高代码的可读性 .
你可以说,那些聪明到能够成为程序员的人会变得足够聪明,以避免引发无括号语句的错误 . 但你真的可以说你从来没有像拼写错误这样简单的东西被绊倒吗?在看大型项目时,这样的细节可能会让人不知所措 .
总有例外情况,但我认为只有当它采用以下形式之一时才会忽略大括号:
// rampion的例子:
for(/ * loop * /)
{
for(/ * loop * /)
for(/ * loop * /)
{
//几行
}
}
否则,我没有问题 .
我偶尔使用最底层的代码(多个使用语句),但除此之外我总是把括号放进去 . 我发现它使代码更清晰 . 显而易见的是,除了缩进之外,语句是块的一部分(因此可能是if等的一部分) .
我见过了
bug咬了我一次(或者更确切地说"me and colleagues" - 我实际上没有介绍这个bug) . 尽管我们当时的编码标准建议在任何地方使用括号 . 我花了很长时间才发现 - 因为你看到了你想要看到的东西 . (这是大约10年前的事 . 也许我现在发现它更快 . )
当然,如果你使用“在行尾的支撑”它减少了额外的线路,但我个人不喜欢这种风格 . (我在工作中使用它,发现它不如我预期的那么令人不愉快,但它仍然有点不愉快 . )
在三个公约中:
和:
和(表示使用开口和右括号的任何缩进样式):
我更喜欢最后一个:
如果所有if语句都以统一的方式编写,我会发现它更容易阅读 .
它可能使软件更健壮,没有bug . 然而所有现代IDE都在评论格式化或违反团队标准(在很多情况下,可以创建自定义格式设置方案并与团队共享) . 我的观点是,如果缩进正确,那么引入错误的风险就会降低一些 .
我更喜欢将布尔表达式和语句执行到不同的行 . 我希望能够为调试目的标记一行 . 即使我是一个交互式操作,我可能会忘记我开始调试的地方,或者至少需要花费一些时间来逐步完成代码(因为我必须在调试期间每次手动标记位置) .
令我印象深刻的是,我在计算机编程领域的同行(你很多)并没有因为在单行块上跳过大括号时潜在错误的前景而感到沮丧 .
我想这意味着我不聪明 . 我多次犯错 . 我调试了其他人的错误 . 因为这个问题,我看到了带有错误的软件(运行VS2002的机器的RDP,你的监视窗口字体会变得很糟糕) .
如果我看看我所做的所有错误,可以通过改变编码风格来避免,列表很长 . 如果我在每种情况下都没有改变我的方法,我可能永远不会成为程序员 . 再说一次,我想我不聪明 . 为了弥补这一点,我长期以来一直是单线模块上大括号的坚定用户 .
也就是说,世界上有些事情发生了变化,使得“你在单行街区上使用括号”的规则与摩西把它带到我们身上相比,现在规则不那么重要了:
一些流行的语言通过让计算机读取缩进来解决问题,就像程序员那样(例如Python) .
我的编辑 automatically formats 对我而言,因此缩小误导的机会大大减少了 .
TDD 意味着如果我引入一个bug,因为我被一个单行块搞糊涂了,我更有可能很快发现这个bug .
Refactoring and language expressiveness 意味着我的块更短,并且单行块的发生频率比使用的更频繁 . 假设有一个无情的ExtractMethod应用程序,我整个程序中可能只有单行块 . (我想知道那会是什么样的?)
事实上,在单行块上无情地重构和省略括号有一个明显的好处:当你看到大括号时,你的头脑中会发出一个小小的警报,说“复杂在这里!小心!” . 想象一下,如果这是常态:
我打算将我的编码约定更改为“单行块可能永远不会有大括号”或“如果你可以将块放在与条件相同的行上,并且它都适合80个字符,省略大括号“ . 走着瞧 .
反对使用大括号的主要论点是它们使用额外的行并且它们需要额外的缩进 .
行(几乎)是免费的,最小化代码中的行数不应该是一个目标 .
缩进与大括号的使用无关 . 在你的级联'使用'示例中,我仍然认为即使你省略大括号也应该缩进它们 .
我非常相信编写简洁明了的代码,但我总是使用花括号 . 我发现它们是快速查看特定代码行存在范围的便捷方式 . 没有歧义,它只是明确地摆在你面前 .
有些人可能会说这是一个偏好的情况,但我发现程序的逻辑流程如果内部一致就更容易理解,我不相信写一个这样的IF语句是一致的;
而另一个像这样;
我更喜欢选择一种一般风格并坚持下去:)
好的,这是一个已经回答死亡的老问题 . 我还有一些事要补充 .
首先,我只想说使用支架 . 它们只能帮助提高可读性,并且可读性(对于您自己和他人!)应该在您的优先级列表中非常高,除非您正在编写程序集 . 总是无法读取的代码,总是会导致错误 . 如果你发现大括号会让代码占用太多空间,那么你的方法可能太长了 . 如果你做得对,大多数或所有方法都应该适合一个屏幕高度,而Find(F3)就是你的朋友 .
现在我的补充:这有一个问题:
尝试设置一个仅在bar()运行时才会被击中的断点 . 您可以通过将光标放在代码的后半部分来在C#中执行此操作,但这并不明显,并且有点痛苦 . 在C中你根本做不到 . 我们处理C代码的最资深的开发人员之一坚持将'if'语句分成两行,因为这个原因 . 我同意他的看法 .
这样做:
其中一个主要问题是当你有一个单行和非一个行的区域,以及与控制语句的分离(
for
,if
,有什么你)和声明的结尾 .例如:
我曾经是“花括号是必须的!”的巨大支持者,但自从采用单元测试后,我发现我的单元测试保护了无括号语句,例如:
通过良好的单元测试,我可以放心地省略大括号的简单语句以提高可读性(是的,这可能是主观的) .
或者,对于类似上面的内容,我可能会将其看起来像:
这样,需要在条件中添加bar()的开发人员更容易识别缺少花括号,并添加它们 .
使用一些个人判断 .
本身很好 . 除非你真的担心白痴晚些时候会这样做:
如果你不担心蠢货,你很好(我不是 - 如果他们不能正确获得基本的代码语法,这是他们最少的问题)>
作为交换,它更具可读性 .
剩下的时间:
只要我记得,这一直是我的最爱 . 另外:
适合我 .
垂直空间本身并不十分相关,可读性也是如此 . 一条直线上的左括号只会停止语法元素的对话,直到你的眼睛向下移动到下一行 . 不是我喜欢的 .
假设你有一些代码:
然后其他人出现并添加:
根据它的写法,bar();现在无条件执行 . 通过包含花括号,可以防止出现这种意外错误 . 代码的编写方式应使得难以或不可能犯这样的错误 . 如果我正在进行代码审查并看到缺少的括号,特别是分布在多行中,我会创建一个缺陷 . 在合理的情况下,将其保持在一行,以便将出现这种错误的可能性再次保持在最低限度 .
减少线条并不是删除大括号的好理由 . 如果你的方法太大,它可能应该重构为更小的部分或重组 . 这样做无疑会增加可读性,而不仅仅是取出括号 .
为了保持代码不会占用大量空间,我使用了书中推荐的技术Code Complete:
我总是在适当时省略它们,例如在你的第一个例子中 . 清晰,简洁的代码我可以通过浏览来查看和理解,比我必须逐行滚动和逐行读取的代码更容易维护,调试和理解 . 我想大多数程序员都会同意这一点 .
如果你开始做多个嵌套,if / else子句等等,它很容易失控,但我认为大多数程序员应该能够知道在哪里画线 .
我觉得它有点像
if ( foo == 0 )
vsif ( 0 == foo )
的论据 . 后者可以防止新程序员的错误(甚至可能偶尔为退伍军人),而前者在维护代码时更容易快速阅读和理解 .大多数情况下,无论是公司还是自由和开放源码软件项目,它都是根深蒂固的编码标准 .
最终,其他人需要了解您的代码,每个开发人员必须弄清楚他们正在处理的代码部分的具体样式是一个主要的时间流失 .
另外,想象一下有人每天不止一次地使用Python和Cish语言......在Python中,缩进是语言的块语义的一部分,并且很容易像你引用的那样犯错误 .
Err更安全 - 只有一个你可能不需要修复的bug .
如果我的所有积木都被卷曲包裹,我个人觉得更安全 . 即使对于单行,这些都是容易防止错误的简单符号 . 它使代码更具可读性,因为您可以清楚地看到块中的内容,而不是将块的主体与块外部的以下语句混淆 .
如果我有一个单行,我通常将其格式化如下:
如果该行太麻烦,请使用以下内容: