12

这是一个较小的风格问题,但您添加到代码中的每一点可读性都很重要。

所以,如果你有:

if (condition) then
{
   // do stuff
}
else
{
   // do other stuff
}

你如何决定是这样还是这样更好:

   if (!condition) then
   {
     // do other stuff
   {
   else
   {
     // do stuff
   }

我的启发是:

  1. 保持条件积极(阅读时减少心理计算)
  2. 将最常见的路径放入第一个块
4

23 回答 23

18

我更喜欢把最常见的路径放在第一位,而且我坚信减少嵌套,所以我会尽可能中断、继续或返回而不是 elsing。我通常更喜欢针对正面条件进行测试,或者将 [和名称] 负面条件反转为正面。

if (condition)
    return;

DoSomething();

我发现,通过大幅减少 else 的使用,我的代码更具可读性和可维护性,当我必须使用 else 时,它​​几乎总是一个更结构化的 switch 语句的绝佳候选者。

于 2008-10-03T12:26:13.063 回答
4

两个(矛盾的)教科书引述:

将 if/else 的最短子句放在最上面

——Allen Holub,“足够的绳子射中自己的脚”,第 52 页

将普通情况放在 if 之后而不是 else 之后

——史蒂夫·麦康奈尔,“代码完成,第 2 版。”,p356

于 2008-10-03T12:55:46.483 回答
3

我更喜欢第一个。条件应该尽可能简单,并且应该相当明显,哪个更简单 out of condition 和 !condition

于 2008-10-03T12:24:42.630 回答
3

这取决于你的流量。对于许多功能,我将使用前置条件:

bool MyFunc(variable) {
    if (variable != something_i_want)
        return false;

    // a large block of code
    // ...
    return true;
}

如果我需要在每种情况下做某事,我会使用一种if (positive_clause) {} else {}格式。

于 2008-10-03T12:28:36.850 回答
3

如果代码是为了检查错误情况,我更喜欢把那个代码放在第一位,然后是“成功”的代码;从概念上讲,这将函数调用及其错误检查代码保持在一起,这对我来说很有意义,因为它们是相关的。例如:

  if (!some_function_that_could_fail())
  {
     // Error handling code
  }
  else
  {
     // Success code
  }
于 2008-10-03T12:31:24.177 回答
3

我同意 Oli 在可能的情况下使用积极的 if 子句。

请永远不要这样做:

if (somePositiveCondition)
else {
    //stuff
}

我曾经在我工作的一个地方经常看到这种情况,并且曾经想知道其中一位编码员是否不明白如何不工作......

于 2008-10-03T12:31:58.670 回答
3

当我查看数据验证时,我尝试将我的条件设为“白名单”——也就是说,我测试我将接受的内容:

if DataIsGood() then
   DoMyNormalStuff
else
   TakeEvasiveAction

而不是反过来,它往往会退化为:

if SomeErrorTest then
  TakeSomeEvasiveAction
else if SomeOtherErrorCondition then
  CorrectMoreStupidUserProblems
else if YetAnotherErrorThatNoOneThoughtOf then
  DoMoreErrorHandling
else
  DoMyNormalStuff
于 2008-10-03T13:02:50.353 回答
2

我知道这并不完全是您要寻找的,但是……许多开发人员使用“保护子句”,即尽快脱离方法的否定“if”语句。那时,真的没有“其他”。

例子:

if (blah == false)
{
    return; // perhaps with a message
}

// do rest of code here...

那里有一些铁杆 c/c++/assembly 家伙会告诉你,你正在破坏你的 CPU !!!(在许多情况下,处理器倾向于“真”语句并尝试“预取”接下来要做的事情......所以理论上任何“假”条件都会刷新管道并且会慢几微秒)。

在我看来,我们正处于“更好”(更易于理解)的代码在几微秒的 CPU 时间中胜出的地步。

于 2008-10-03T12:39:22.930 回答
2

我认为对于单个变量,not 运算符足够简单,并且命名问题开始变得更加相关。

永远不要将变量命名为 not_X,如果需要,请使用词库并找到相反的词。我见过很多糟糕的代码,比如

if (not_dead) {
} else {
}

而不是显而易见的

if (alive) {
} else {
}

然后你可以理智地使用(非常可读,无需反转代码块)

if (!alive) {
} else {
}

如果我们谈论更多变量,我认为最好的规则是简化条件。一段时间后,项目往往会遇到以下情况:

if (dead || (!dead && sleeping)) {
} else {
}

这转化为

if (dead || sleeping) {
} else {
}

始终注意条件是什么样的以及如何简化它们。

于 2008-10-03T12:47:51.007 回答
2

软件是知识获取。您正在编码某人关于如何做某事的知识。

该软件应该适合问题的“自然”。如有疑问,请询问其他人,看看人们实际所说和所做的。

“常见”情况是什么都不做的情况呢?然后怎样呢

if( common ) {
    // pass
}
else {
    // great big block of exception-handling folderol
}

或者你这样做?

if( ! common ) {
    // great big block of except-handling folderol
}

“总是积极的”规则并不是你首先想要的。您想查看更多类似以下的规则。

  1. 总是自然的——它应该读起来像英语(或者你组织中的任何通用语言。)
  2. 在可能的情况下,首先是常见情况——所以它们看起来很常见。
  3. 尽可能使用正逻辑;否定逻辑可以用在通常这样说的地方,或者常见的情况是什么都不做的地方。
于 2008-10-03T12:57:45.763 回答
2

如果两条路径中的一条很短(1 到 10 行左右),而另一条则更长,我遵循这里提到的 Holub 规则,并将较短的一段代码放在 if.xml 中。这使得在查看代码时更容易在一个屏幕上查看 if/else 流程。

如果那是不可能的,那么我构造使条件尽可能简单。

于 2008-10-03T13:01:57.470 回答
1

对我来说,这取决于条件,例如:

if (!PreserveData.Checked)
{  resetfields();}

我倾向于用我想要的逻辑与自己交谈,并将其编码为我脑海中的小声音。

于 2008-10-03T12:29:54.820 回答
1

您通常可以在不切换 if / else 块的情况下使条件为正。

改变

   if (!widget.enabled()) {
     // more common 
   } else {
     // less common 
   }

   if (widget.disabled()) {
     // more common 
   } else {
     // less common
   }
于 2008-10-03T13:05:13.407 回答
1

Intel Pentium 分支预测为“if”情况预取指令。如果它改为跟随“else”分支:它会刷新指令流水线,导致停顿。

如果您非常关心性能:将最可能的结果放在“if”子句中。

我个人把它写成

if (expected)
{
   //expected path
}
else
{
   //fallback other odd case
} 
于 2008-10-03T13:33:26.813 回答
1

如果您同时具有真假条件,那么我会选择肯定条件 - 这可以减少混淆,并且总的来说我相信您的代码更易于阅读。

另一方面,如果您使用 Perl 之类的语言,特别是如果您的错误条件是错误条件或最常见的条件,则可以使用“除非”结构,它执行代码块,除非条件为真(即 if 的反面):

unless ($foo) {
    $bar;
}
于 2008-10-03T14:05:57.543 回答
1

首先,让我们先把最好避免使用“else”的情况放在一边(我希望每个人都同意这种情况确实存在,确定这种情况可能应该是一个单独的话题)。

所以,让我们假设必须有一个“else”子句。

我认为可读性/可理解性至少强加了三个关键要求或规则,不幸的是,它们经常相互竞争:

  1. 第一个块(“if”块)越短,就越容易掌握整个“if-else”结构。当“if”块足够长时,很容易忽略“else”块的存在。

  2. 当“if”和“else”路径在逻辑上不对称时(例如“正常处理”与“错误处理”),在独立的“if-else”构造中,哪条路径是第一条路径和第二条路径并不重要. 然而,当有多个“if-else”结构彼此靠近时(包括嵌套),并且当所有这些“if-else”结构具有相同类型的不对称性时 - 安排这些不对称路径非常重要始终如一。

    同样,它可以是“如果……正常路径……否则……异常路径”,也可以是“如果……异常路径……否则……正常路径”,但不应该是这两种变体的混合。

    在所有其他条件相同的情况下,对大多数人来说,将正常路径放在首位可能更自然(我认为这更多的是关于心理学而不是美学:-)。

  3. 以否定开头的表达式通常比不以否定开头的表达式可读性/可理解性差。

所以,我们有这三个相互竞争的要求/规则,真正的问题是:它们中的哪一个比其他的更重要。对于 Allen Holub 来说,第 1 条规则可能是最重要的一条。对于史蒂夫·麦康奈尔来说——这是规则#2。但我不认为你真的可以只选择这些规则中的一个作为单一的quideline。

我敢打赌,您已经猜到了我个人的优先事项(从我订购上述规则的方式来看:-)。

我的理由很简单:

  • 第 1 条规则是无条件的,无法规避。如果其中一个块太长以至于它跑出屏幕 - 它必须成为“其他”块。(不,仅仅为了减少“if”或“else”块中的行数而机械地创建函数/方法并不是一个好主意!我假设每个块已经具有逻辑上合理的最小行数。 )

  • 规则 #2 涉及很多条件:多个“if-else”结构,都具有相同类型的不对称性,等等。所以它在很多情况下并不适用。

    另外,我经常观察到以下有趣的现象:当第 2 条规则适用并且使用得当时,它实际上与第 1 条规则并不冲突!例如,每当我有一堆“正常与异常”不对称的“if-else”语句时,所有“异常”路径都比“正常”路径短(反之亦然)。我无法解释这种现象,但我认为这只是代码组织良好的标志。换句话说,每当我看到规则#1 和#2 发生冲突的情况时,我就会开始寻找“代码异味”,而且我经常会找到一些;重构之后 - tada!在规则 #1 和规则 #2 之间选择不再痛苦,:-)

  • 最后,规则#3 的范围最小,因此最不重要。

    此外,正如其他同事在此提到的,使用此规则“作弊”通常很容易(例如,写“if(disabled),,”而不是“if(!enabled)...”)。

我希望有人能对这个作品有所了解...

于 2008-10-31T09:54:29.653 回答
0

作为一般规则,如果一个明显大于另一个,我将较大的一个作为if块。

于 2008-10-03T12:32:36.717 回答
0
  1. 把公共路径放在第一位
  2. 化消极为积极(!full == empty
于 2008-10-03T12:32:46.047 回答
0

如果您必须有多个出口点,请将它们放在第一位并明确:

if TerminatingCondition1 then
  Exit
if TerminatingCondition2 then
  Exit

现在我们可以使用通常的东西进行处理:

if NormalThing then
  DoNormalThing
else
  DoAbnormalThing
于 2008-10-03T12:54:13.443 回答
0

我总是把最有可能的放在第一位。

在 Perl 中,我有一个额外的控制结构来帮助解决这个问题。如果的倒数。

unless (alive) {
     go_to_heaven;
} else {
     say "MEDIC";
}
于 2008-10-03T13:40:34.037 回答
0

您应该始终将最可能的情况放在首位。除了更具可读性之外,它还更快。这也适用于 switch 语句。

于 2008-10-03T14:50:28.093 回答
0

当谈到我如何设置 if 语句时,我很可怕。基本上,我根据我正在寻找的内容进行设置,这导致一切都不同。

if (userinput = null){
explodeViolently();
} else {
实际做事;
}

或者类似

if (1+1=2) {
do stuff;
} 其他 {
爆炸暴力();
}

if/else 语句的哪个部分实际上为我做事是我的一个坏习惯。

于 2008-10-03T15:38:16.500 回答
0

我通常把肯定的结果(所以方法)放在开头,所以:

if(condition)
{
doSomething();
}
else
{
System.out.println("condition not true")
}

但是,如果要使用的方法条件必须为假,我会这样做:

if(!condition)
{
doSomething();
}
else
{
System.out.println("condition true");
}
于 2012-07-16T13:54:35.943 回答