在IF块中放置什么,在ELSE块中放置什么?

时间:2020-03-06 15:04:18  来源:igfitidea点击:

这是一个次要的样式问题,但是我们添加到代码中的每一点可读性都很重要。

因此,如果我们有:

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

我们如何确定像这样更好还是这样:

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

我的试探法是:

  • 保持病情积极(阅读时无需费神)
  • 将最常见的路径放入第一块

解决方案

我喜欢第一个。条件应该尽可能简单,并且应该很明显,这比条件和!condition更简单。

我更喜欢将最常见的路径放在第一位,并且我坚信减少嵌套的做法,因此我会尽可能地打破,继续或者返回而不是费劲。我通常更喜欢测试积极的条件,或者将消极的条件颠倒[和命名]为积极的条件。

if (condition)
    return;

DoSomething();

我发现通过大幅度减少其他代码的使用,我的代码更易读和可维护,当我不得不使用其他代码时,它几乎总是适合使用更有条理的switch语句。

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

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

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

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

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

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

我倾向于用自己想要的逻辑对自己说话,并将其编码为脑海中很小的声音。

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

if (!some_function_that_could_fail())
  {
     // Error handling code
  }
  else
  {
     // Success code
  }

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

请永远不要这样做:

if (somePositiveCondition)
else {
    //stuff
}

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

通常,如果一个明显大于另一个,则将较大的一个设为" if"块。

  • 把共同的道路放在首位
  • 把消极的king变成积极的(!full == empty)

我知道这并不是我们要查找的内容,但是...许多开发人员使用"保护子句",即,否定的" if"语句,该语句会尽快脱离该方法。在这一点上,确实没有"其他"。

例子:

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

// do rest of code here...

那里有一些核心的c / c ++ / assembly家伙,他们会告诉我们我们正在破坏CPU! (在许多情况下,处理器倾向于使用" true"语句,并尝试"预取"下一个要做的事情……因此,从理论上讲,任何" false"条件都将冲洗管道并减慢微秒的时间)。

在我看来,我们处于"更好"(更易于理解)的代码胜过微秒CPU时间的地步。

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

切勿命名变量not_X,如果需要,请使用同义词库查找反义词。我看过很多糟糕的代码,例如

if (not_dead) {
} else {
}

而不是显而易见的

if (alive) {
} else {
}

然后,我们可以明智地使用(可读性强,无需反转代码块)

if (!alive) {
} else {
}

如果我们要谈论更多的变量,我认为最好的规则是简化条件。一段时间后,项目趋向于获得以下条件:

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

转化为

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

始终注意条件如何以及如何简化它们。

如果必须有多个出口点,请将它们放在第一位并使其清楚:

if TerminatingCondition1 then
  Exit
if TerminatingCondition2 then
  Exit

现在,我们可以继续进行通常的工作:

if NormalThing then
  DoNormalThing
else
  DoAbnormalThing

两个(矛盾的)教科书名言:

Put the shortest clause of an if/else
  on top

-艾伦·霍鲁布(Allen Holub),"用绳索绑住自己的脚",第52页

Put the normal case after the if rather than after the else

-史蒂夫·麦康奈尔(Steve McConnell),"代码完成,第二版",p356

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

该软件应适合该问题的"自然"部分。如有疑问,请问其他人,看看人们的实际言行。

在"常见"案件什么都不做的情况下该怎么办?然后怎样呢

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

还是你这样做?

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

"永远积极"的规则并不是我们真正想要的。我们想看如下规则。

  • 总是很自然-读起来应该像英语(或者组织中的通用语言)。
  • 在可能的情况下,首先是常见情况-因此它们看起来很常见。
  • 尽可能使用正逻辑;否定逻辑可以用在通常这样说的地方,或者是在无所事事的情况下使用。

如果两条路径中的一条非常短(大约1至10行),而另一条更长,则遵循此处提到的Holub规则,并将较短的代码放入if中。这使得在查看代码时更容易在一个屏幕上查看if / else流程。

如果这不可能,那么我将结构简化为尽可能简单的条件。

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

if DataIsGood() then
   DoMyNormalStuff
else
   TakeEvasiveAction

而不是相反,它倾向于退化为:

if SomeErrorTest then
  TakeSomeEvasiveAction
else if SomeOtherErrorCondition then
  CorrectMoreStupidUserProblems
else if YetAnotherErrorThatNoOneThoughtOf then
  DoMoreErrorHandling
else
  DoMyNormalStuff

通常,我们可以使条件为正,而无需在if / else块之间切换。

改变

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

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

英特尔奔腾分支预测会针对" if"情况预取指令。相反,如果它遵循" else"分支:则刷新指令管道,从而导致停顿。

如果我们非常在意性能,请在" if"子句中添加最可能的结果。

我个人写为

if (expected)
{
   //expected path
}
else
{
   //fallback other odd case
}

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

在Perl中,我有一个额外的控制结构来帮助实现这一点。 if的倒数。

unless (alive) {
     go_to_heaven;
} else {
     say "MEDIC";
}

如果我们同时具有真假条件,那么我将选择正条件,这会减少混乱,总的来说,我认为这会使代码更易于阅读。

另一方面,如果我们使用的是Perl之类的语言,尤其是如果错误条件是错误条件或者最常见的条件,则可以使用"除非"结构,该结构将执行代码块,除非该条件是真实的(即与if相反):

unless ($foo) {
    $bar;
}

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

关于如何设置if语句,我感到很恐怖。基本上,我是根据我要寻找的内容进行设置的,这导致一切都与众不同。
如果(userinput = null){
explodeViolently();
} 别的 {
实际做事;
}
或者类似的东西
如果(1 + 1 = 2){
做东西;
} 别的 {
explodeViolently();
}

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

首先,让我们把情况放在一边,最好不要使用"其他"(我希望每个人都同意这种情况确实存在,并确定这种情况可能是一个单独的话题)。

因此,我们假设必须有一个" else"子句。

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

  • 第一个块(" if"块)越短,就越容易掌握整个" if-else"结构。当" if"块足够长时,忽略" else"块的存在变得太容易了。
  • 当" if"和" else"路径在逻辑上是不对称的(例如"正常处理"与"错误处理")时,在独立的" if-else"构造中,哪个路径是第一路径,哪个路径是第二路径并不重要。 。但是,当有多个彼此相邻的" if-else"构造(包括嵌套),并且所有这些" if-else"构造都具有相同的不对称性时,这时布置这些非对称路径非常重要始终如一。同样,可以全部使用"如果...正常路径... else ...异常路径",或者全部使用"如果...异常路径... else ...正常路径",但是不应该这样是这两个变体的混合体。在所有其他条件相同的情况下,对大多数人来说,将正常道路放在首位可能更自然(我认为这更多是关于心理学而不是美学:-)。
  • 以否定开头的表达式通常比没有表达式的可读性/可理解性低。

因此,我们有这三个相互竞争的需求/规则,而真正的问题是:其中哪一个比其他的更为重要。对于Allen Holub来说,规则#1可能是最重要的。对于史蒂夫·麦康奈尔(Steve McConnell),这是规则2. 但是我认为我们真的不能只选择其中一条规则作为一条基德线。

我敢打赌,我们已经在这里猜到了我的个人优先事项(根据我订购上述规则的方式:-)。

我的原因很简单:

  • 规则#1是无条件的,无法规避。如果其中一个块太长以至于无法在屏幕上显示-它必须成为" else"块。 (不,机械地创建函数/方法只是减少" if"或者" else"块中的行数不是一个好主意!我假设每个块已经具有逻辑上合理的最小行数。 )
  • 规则2涉及很多条件:多个" if-else"构造,所有构造都具有相同的不对称性,等等。因此,它仅在许多情况下不适用。此外,我经常观察到以下有趣的现象:当规则2确实适用并且正确使用时,它实际上与规则1不冲突!例如,每当我有一堆具有"正常与异常"不对称性的" if-else"语句时,所有"异常"路径都比"正常"路径短(反之亦然)。我无法解释这种现象,但是我认为这只是良好的代码组织的标志。换句话说,每当我看到规则#1和#2发生冲突的情况时,我就会开始寻找"代码气味",而且我经常发现一些"代码气味"。重构后-多田!在规则1和规则2之间再无痛苦的选择,:-)
  • 最后,规则3的范围最小,因此最不重要。另外,正如其他同事在此所述,通常很容易使用此规则"作弊"(例如,编写" if(disabled),"而不是" if(!enabled)...")。

我希望有人可以对这个作品有所了解。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。