是否有充分的理由说明在函数中只有一个return语句是一个更好的实践?

或者在逻辑上正确的情况下,可以从函数中返回,这意味着函数中可能有许多返回语句?


当前回答

使用单一出口点可以降低圈复杂度,因此,从理论上讲,可以降低在修改代码时引入错误的可能性。然而,实践往往表明需要更务实的方法。因此,我倾向于只有一个出口点,但如果可读性更好,允许我的代码有多个出口点。

其他回答

我想说的是,你应该有尽可能多的需要,或者任何使代码更干净的(如保护子句)。

我个人从来没有听过/见过任何“最佳实践”说你应该只有一个返回语句。

在大多数情况下,我倾向于根据逻辑路径尽快退出函数(保护子句就是一个很好的例子)。

如果你最终得到了很多返回值,那么你的代码可能有问题。否则,我同意有时能够从子例程的多个位置返回是很好的,特别是当它使代码更干净的时候。

Perl 6:坏例子

sub Int_to_String( Int i ){
  given( i ){
    when 0 { return "zero" }
    when 1 { return "one" }
    when 2 { return "two" }
    when 3 { return "three" }
    when 4 { return "four" }
    ...
    default { return undef }
  }
}

这样写会更好吗

Perl 6:好例子

@Int_to_String = qw{
  zero
  one
  two
  three
  four
  ...
}
sub Int_to_String( Int i ){
  return undef if i < 0;
  return undef unless i < @Int_to_String.length;
  return @Int_to_String[i]
}

注意,这只是一个简单的例子

我能想到的一个很好的理由是代码维护:您有一个单一的退出点。如果你想改变结果的格式,…,它的实现要简单得多。此外,为了调试,你可以在那里插入一个断点:)

话虽如此,我曾经不得不在一个库中工作,那里的编码标准强制要求“每个函数一个返回语句”,我发现这相当困难。我写了很多数值计算代码,经常有“特殊情况”,所以代码最终很难跟上……

我目前正在开发一个代码库,其中有两个人盲目地赞同“单点退出”理论,我可以告诉你,从经验来看,这是一个非常可怕的实践。这使得代码极其难以维护,我将向您展示原因。

根据“单点退出”理论,你不可避免地会得到这样的代码:

function()
{
    HRESULT error = S_OK;

    if(SUCCEEDED(Operation1()))
    {
        if(SUCCEEDED(Operation2()))
        {
            if(SUCCEEDED(Operation3()))
            {
                if(SUCCEEDED(Operation4()))
                {
                }
                else
                {
                    error = OPERATION4FAILED;
                }
            }
            else
            {
                error = OPERATION3FAILED;
            }
        }
        else
        {
            error = OPERATION2FAILED;
        }
    }
    else
    {
        error = OPERATION1FAILED;
    }

    return error;
}

这不仅使代码难以理解,而且以后还需要返回并在1和2之间添加一个操作。您必须缩进整个该死的函数,并确保所有if/else条件和大括号都正确匹配。

这种方法使代码维护极其困难,而且容易出错。

我认为在不同的情况下,不同的方法更好。例如,如果您应该在返回之前处理返回值,则应该有一个退出点。但在其他情况下,使用多次返回会更舒服。

一个音符。如果在某些情况下,你应该在返回之前处理返回值,但不是所有情况下,最好的解决方案(IMHO)是定义一个像ProcessVal这样的方法,并在返回之前调用它:

var retVal = new RetVal();

if(!someCondition)
    return ProcessVal(retVal);

if(!anotherCondition)
   return retVal;