"if, if, if"或"if, else if, else if, else"

To "if, if, if" or to "if, else if, else if, else"

本文关键字:if else      更新时间:2023-10-16

我正在编写一些用于数据分析的代码,并且必须根据某些标准排除样本。在实践中,我最终编写了这样的代码:

bool Test(SampleType sample)
{
  if( ! SubTest1(sample) )
    return false;
  if( ! SubTest2(sample) )
    return false;
  if( ! SubTest3(sample) )
    return false;
  return true;
}

对我来说,以下内容似乎是等价的:

bool Test(SampleType sample)
{
  if( ! SubTest1(sample) )
    return false;
  else if( ! SubTest2(sample) )
    return false;
  else if( ! SubTest3(sample) )
    return false;
  else 
    return true;
}

在计算成本方面有差异吗?在可扩展性/可维护性、美观性等方面是否存在可争议的优先选择?

我知道这可能是一个无关紧要的问题,但是一旦这些问题在我的脑海里挥之不去,我就需要找到答案。

PS:如果有人关心,我的实际代码作为15/09可以在下面找到:http://folk.uio.no/henrikq/conf.tgz

编译器为两个版本生成相同的代码。但是第一个版本在可维护性方面比第二个版本要好。

遇到return语句时退出;因此,在即将到来的if中保留else是没有用的。它使开发人员更好地理解代码。

同样,如果这是文字代码,那么你仍然可以收缩为

bool Test(SampleType sample)
{
  return (SubTest1(sample) && SubTest2(sample) && SubTest3(sample));
}

我会这样做:

return SubTest1(sample) && SubTest2(sample) && SubTest3(sample);

这不会提高性能,但函数的功能可能(也可能不)更明显。

两者在行为上是完全等同的,编译器可能会为两者发出相同的机器码。

它们在可读性方面甚至没有太大的区别——它们都有相同数量的嵌套。

在可读性方面,

bool Test( SampleType sample )
{
    return SubTest1( sample )
        && SubTest2( sample )
        && SubTest3( sample );
}

比你的任何一个选项都清晰得多。否则,你肯定希望else明确表示,一旦有一个条件只要满足了,其他的都不需要测试。

两者完全相同。编译器可能会找出如何优化它们,以便发出相同的机器码。我将选择第一个代码,因为它更容易阅读。

我想象不出这对性能有什么影响。

如果它们是独立的测试,我将使用第一个,并且您只想在其中一个成功后退出,如果它在一组逻辑替代方案之间进行选择,我将使用第二个。

据我所知,生成的机器代码没有区别。除此之外,谁在乎呢?这段代码有性能问题吗?性能是一个困难的主题,通常应该留在项目结束时,只有当有性能问题,他们应该被发现和修复,他们实际上存在,而不是在你认为他们可能提前。

这主要取决于编译器如何优化生成的代码。

if(.)通常用compare_to_zero指令翻译,后面跟着条件跳转。

在你的例子中,这将是

CMP(c1)
RETZ
CMP(c2)
RETZ
CMP(c3)
RETZ

或(带else-s)

   CMP(c1)
   JNZ(a1)
   RET
a1:CMP(c2)
   JNZ(a2)
   RET
a2:CMP(c3)
   JNZ(a3)
   RET
a3:RET

优化器的第二次传递将看到跳转链,反转then/else(和Z/NZ)跳过跳转,处于"跳转到下一个"点,给出之前的代码。

这取决于语言和周围的api

第一个解决方案是典型的命令式方法,重点是检查某些事情的行为:如果a中止,如果b中止,如果c中止,成功。

第二种解决方案是一种更实用的方法,可以将其读作数学定义中的花括号(如:fac(n) = { n <= 1: 1, n > 1: n * fac(n-1))。

应选择与环境相匹配的解决方案。在Java、Python等中,它将是第一个。在ruby中,第二个就可以了。

有一个好的做法叫做"一个入口,一个出口"。这意味着在一个函数中最好只有一个返回

现在,你的函数是简单的,但在将来,它可能会增长,变得更复杂,分配临时变量必须被释放,等等。

所以最好在任何地方都使用好的实践。它被称为"防御性编程",防御人类的失败(我和我的同事)。

我会这样写:

bool Test(SampleType sample)
{
  bool bRet = true; // by default, set it to the most "defensive" value which will cause the less harm or make the problem evident
  // in the future, you may have inits and allocations here
  if ( !SubTest1(sample) )
    bRet = false; // don't match
  else if ( !SubTest2(sample) )
    bRet = false; // don't match
  else if ( !SubTest3(sample) )
    bRet = false; // don't match
  else
    ; // bRet stays true
  // thanks to the single point of exit, you can do things like that
  if (bRet)
     log("... match");
  else
     log("...no match")
  // here you clean temporary resources...
  return bRet;
}

如果您想提高性能,最好的方法是将SubTestX函数按最佳顺序排列,以便最不匹配的函数排在前面,因此需要较少的测试来发现它不匹配。