对于单行if或循环使用大括号(即{})的目的是什么?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (10)
  • 关注 (0)
  • 查看 (130)

例如,以下面这个奇怪的代码为例:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
{
    if (i % 2 == 0)
    {
        j++;
    }
}

并将其替换为:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;

使用第一个版本有什么好处?

提问于
用户回答回答于

让我们也尝试修改i当我们增加j:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
        i++;

Python看起来不错,但实际上并非如此,因为它相当于:

int j = 0;
for (int i = 0 ; i < 100 ; ++i)
    if (i % 2 == 0)
        j++;
i++;

当然,这是一个愚蠢的错误,但即使是一个有经验的程序员也能做出这样的错误。

ta.speot.is的答案指出了另一个很好的理由。

第三个我能想到的是嵌套如果是:

if (cond1)
   if (cond2) 
      doSomething();

假设你现在想doSomethingElse()何时cond1未满足(新特性)。因此:

if (cond1)
   if (cond2) 
      doSomething();
else
   doSomethingElse();

这显然是错误的,因为else与内在联系if...

我回答的问题是:

使用第一版本有什么好处?

我已经描述过了。有一些好处。但我不完全支持

总是使用{}块--即使对于一行//不确定,为什么???

我并不是说总是使用{}块,这是一个足够简单的条件和行为。 如果你怀疑某人稍后可能会进来并更改你的代码以添加功能,请执行。

用户回答回答于

能想到的最相关的例子是:

if(someCondition)
   if(someOtherCondition)
      DoSomething();
else
   DoSomethingElse();

如果声明是:

if(someCondition)
   DoSomething();
用户回答回答于

我在用{}到处都是,除了一些明显的例子。单行是其中一种情况:

if(condition) return; // OK

if(condition) // 
   return;    // and this is not a one-liner 

在返回前添加一些方法可能会对你造成伤害。缩进表示在满足条件时返回正在执行,但它将始终返回。

C#中的其他使用状态的示例

using (D d = new D())  // OK
using (C c = new C(d))
{
    c.UseLimitedResource();
}

相当于

using (D d = new D())
{
    using (C c = new C(d))
    {
        c.UseLimitedResource();
    }
}
用户回答回答于

为了增加上述非常合理的建议,我在重构一些代码时遇到的一个例子是:我正在修改一个非常大的代码库,以从一个API切换到另一个API。第一个API调用了如下所示的公司ID:

setCompIds( const std::string& compId, const std::string& compSubId );

而替换则需要两个调用:

setCompId( const std::string& compId );
setCompSubId( const std::string& compSubId );

我开始使用正则表达式来改变它,这是非常成功的。我们还传递了代码意式这确实使它更加可读性更强。然后,在审查过程的一部分过程中,我发现在某些有条件的情况下,它正在改变这种情况:

if ( condition )
   setCompIds( compId, compSubId );

对此:

if ( condition )
   setCompId( compId );
setCompSubId( compSubId );

这显然不是我们所需要的。我不得不从头开始,把替换的东西完全放在块内,然后手动修改最后看起来很傻的东西(至少不会不正确)。

我注意到astyle现在有了--add-brackets选项,它允许你在没有的情况下添加括号,如果你发现自己和我在同一个位置,我强烈推荐这个选项。

用户回答回答于

它更直观,更容易理解。

它确保了当新用户可能在不知不觉中错过了{}同时添加一个新代码语句。

用户回答回答于

我的2c:

Use Indentation

显然

永远不要依赖运算符优先级--始终使用括号

我不会使用“never”和“always”这个词,但总的来说,我认为这条规则是有用的。在某些语言(Lisp,Smalltalk)中,这不是一个问题。

始终使用{}块--即使对于一行

我从来没有这样做,也从来没有一个问题,但我可以看到它如何可以对学生有益,尤其是。如果他们以前学过Python。

比较左侧的Const对象

这损失了可读性。编译代码时只需使用最大警告级别即可。

对>=0的变量使用无符号

好吧。

删除后将指针设置为NULL-双删除保护

永远不要有指向已删除或不存在对象的指针.

用户回答回答于

我正在编写的代码库是由对大括号有病态厌恶的人编写的代码,对于后来出现的人来说,它确实对可维护性有很大的影响。

我遇到的最常见的问题例子是:

if ( really incredibly stupidly massively long statement that exceeds the width of the editor) do_foo;
    this_looks_like_a_then-statement_but_isn't;

因此,当我想添加一个时间语句时,如果我不小心的话,我很容易就会得到这样的结果:

if ( really incredibly stupidly massively long statement that exceeds the width of the editor) do_foo;
{
    this_looks_like_a_then-statement_but_isn't;
    i_want_this_to_be_a_then-statement_but_it's_not;
}

考虑到花费大约1秒钟的时间来添加花括号,并且可以在最少的几分钟调试时间内为你节省大量的时间,为什么不去选择减少歧义的选项呢?

用户回答回答于

让我说,我同意你的看法:规则是多余的,我不会建议。诚然,如果你总是添加大括号,理论上可以防止错误。

开始时考虑一个有很多guard子句的函数:

void some_method(obj* a, obj* b)
{
    if (a == nullptr)
    {
        throw null_ptr_error("a");
    }
    if (b == nullptr)
    {
        throw null_ptr_error("b");
    }
    if (a == b)
    {
        throw logic_error("Cannot do method on identical objects");
    }
    if (not a->precondition_met())
    {
        throw logic_error("Precondition for a not met");
    }

    a->do_something_with(b);
}

下面的代码更加可读:

void some_method(obj* a, obj* b)
{
    if (a == nullptr)
        throw null_ptr_error("a");
    if (b == nullptr)
        throw null_ptr_error("b");
    if (a == b)
        throw logic_error("Cannot do method on identical objects");
    if (not a->precondition_met())
        throw logic_error("Precondition for a not met");

    a->do_something_with(b);
}

同样

matrix operator +(matrix const& a, matrix const& b) {
    matrix c(a.w(), a.h());

    for (auto i = 0; i < a.w(); ++i)
        for (auto j = 0; j < a.h(); ++j)
            c(i, j) = a(i, j) + b(i, j);

    return c;
}

与之比较:

matrix operator +(matrix const& a, matrix const& b) {
    matrix c(a.w(), a.h());

    for (auto i = 0; i < a.w(); ++i)
    {
        for (auto j = 0; j < a.h(); ++j)
        {
            c(i, j) = a(i, j) + b(i, j);
        }
    }

    return c;
}

第一个代码是简洁的; 第二个代码是臃肿的。

用户回答回答于

我对这位讲师的能力表示怀疑。考虑到他的观点:

  1. 有人真的会写(或想读)(b*b) - ((4*a)*c)是吗?有些先例是显而易见的(或者应该是的),而额外的括号只会增加混乱。
  2. 格式化条件和循环有两个广泛的约定:if(Cond){code;}

首先,我同意他的观点。开口{没有那么明显,所以最好假设它总是在那里。然而,在第二个例子中,我(以及我工作过的大多数人)省略单个语句的大括号是没有问题的。(当然,只要缩进是系统的,并且你使用这种样式是一致的。(还有很多非常优秀的程序员,他们编写的代码可读性很强,即使在格式化第一种方式时也省略了大括号。)

  1. 事情就像if ( NULL == ptr )丑陋到足以阻碍可读性。直观地写出比较,任何使代码不自然的东西都会使其可读性降低。
  2. 除了int专门用于特殊情况。对于经验丰富的C和C++程序员,使用unsigned信号位操作员。C++没有真正的基数类型(或任何其他有效的子范围类型);unsigned由于升级规则,数值不起作用。没有算术运算会有意义的数值,如序号,可能是unsigned然而,我反驳它,因为它发送了错误的信息:按位操作也没有意义。 基本规则是整数类型是int,_unless_使用另一个类型是有重要原因的。
  3. 系统地这样做是有误导性的,实际上并不能防止任何事情的发生。在严格的OO代码中,delete this;是最常见的情况(你不能设置thisNULL),或者其他情况下,大多数delete在析构函数中,所以以后不能访问指针。并将其设置为NULL不会对任何其他的指针产生任何影响。系统地将指针设置为NULL给人一种虚假的安全感,并不能买到任何东西。
用户回答回答于

如果你不使用{}例如:

if (condition)
  do_something();
else
  do_something_else();

must_always_do_this();

如果你用单行注释注释掉do_something_else(),你将会得到这个结果:

if (condition)
  do_something();
else
  //do_something_else();

must_always_do_this();

它会编译,但是must_always_do_this()并不总是被称为。

我们的代码库中有这个问题,有人在发布之前很快就禁用了一些功能。

所属标签

可能回答问题的人

  • 西风

    renzha.net · 站长 (已认证)

    7 粉丝1 提问9 回答
  • 四无君

    0 粉丝0 提问3 回答
  • 旺仔小小鹿

    社区 · 运营 (已认证)

    46 粉丝0 提问2 回答
  • 拉布拉多拉不多

    1 粉丝0 提问2 回答

扫码关注云+社区

领取腾讯云代金券