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

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


当前回答

唯一重要的问题是“如何使代码更简单、更易读、更容易理解?”如果使用多个返回会更简单,那么就使用它们。

其他回答

这可能是一个不寻常的观点,但我认为任何相信多个return语句是有利的人都从未在只支持4个硬件断点的微处理器上使用过调试器。:-)

虽然“箭头代码”的问题是完全正确的,但当使用多个return语句时,一个问题似乎消失了,那就是在使用调试器的情况下。您没有一个方便的万能位置来放置断点,以保证您将看到退出,从而看到返回条件。

使用单一的退出点有好处,就像不可避免的“箭头”编程也有坏处一样。

如果在输入验证或资源分配期间使用多个出口点,我尝试将所有“错误出口”非常明显地放在函数的顶部。

“SSDSLPedia”的Spartan Programming文章和“Portland Pattern Repository’s Wiki”的单一函数出口点文章都对此有一些深刻的争论。当然,还有这篇文章要考虑。

例如,如果您真的需要一个单一的退出点(在任何不支持异常的语言中),以便在一个地方释放资源,我发现仔细应用goto是很好的;请看这个相当做作的例子(压缩以节省屏幕空间):

int f(int y) {
    int value = -1;
    void *data = NULL;

    if (y < 0)
        goto clean;

    if ((data = malloc(123)) == NULL)
        goto clean;

    /* More code */

    value = 1;
clean:
   free(data);
   return value;
}

就我个人而言,总的来说,我不喜欢箭头编程,而不喜欢多个出口点,尽管两者在正确应用时都很有用。当然,最好的方法是将程序的结构设计成两者都不需要。将你的函数分解成多个块通常会有所帮助:)

尽管在这样做的时候,我发现我最终得到了多个出口点,就像在这个例子中,一些较大的函数被分解成几个较小的函数:

int g(int y) {
  value = 0;

  if ((value = g0(y, value)) == -1)
    return -1;

  if ((value = g1(y, value)) == -1)
    return -1;

  return g2(y, value);
}

根据项目或编码指南的不同,大多数样板代码可以被宏替换。作为旁注,这样分解可以使函数g0、g1、g2非常容易单独测试。

显然,在面向对象和支持异常的语言中,我不会使用这样的if语句(或者根本不会使用,如果我可以用足够少的努力就能摆脱它的话),代码将更加简单。和non-arrowy。大多数非最终回报可能是例外。

简而言之,

少回报比多回报好 多于一次的返回比巨大的箭头更好,并且保护条款通常是可以的。 在可能的情况下,例外可能/应该取代大多数“保护条款”。

我通常的策略是在函数的末尾只有一个return语句,除非通过添加更多的return语句来大大降低代码的复杂性。事实上,我是Eiffel的粉丝,它通过没有return语句强制执行唯一的返回规则(只有一个自动创建的'result'变量来放入结果)。

当然,在某些情况下,有多个返回值的代码比没有返回值的代码更清晰。有人可能会说,如果一个函数太复杂,没有多个return语句就无法理解,那么就需要更多的返工,但有时对这种事情采取务实的态度是好的。

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

是的,有:

The single exit point gives an excellent place to assert your post-conditions. Being able to put a debugger breakpoint on the one return at the end of the function is often useful. Fewer returns means less complexity. Linear code is generally simpler to understand. If trying to simplify a function to a single return causes complexity, then that's incentive to refactor to smaller, more general, easier-to-understand functions. If you're in a language without destructors or if you don't use RAII, then a single return reduces the number of places you have to clean up. Some languages require a single exit point (e.g., Pascal and Eiffel).

这个问题通常被提出为多个返回或深度嵌套的if语句之间的错误二分法。几乎总有第三种解决方案,它是线性的(没有深度嵌套),只有一个出口点。

更新:MISRA的指导方针显然也提倡单次退出。

需要澄清的是,我并不是说拥有多个回报总是错误的。但如果有其他等价的解决方案,有很多很好的理由选择单一回报的方案。

在一个没有副作用的函数中,没有理由有多个返回值,你应该用函数式的风格来编写它们。在有副作用的方法中,事情更有顺序(时间索引),因此您使用命令式风格编写,使用return语句作为停止执行的命令。

换句话说,如果可能的话,尽量采用这种风格

return a > 0 ?
  positively(a):
  negatively(a);

在这

if (a > 0)
  return positively(a);
else
  return negatively(a);

如果您发现自己编写了几层嵌套的条件,可能有一种方法可以重构它,例如使用谓词列表。如果您发现If和else在语法上相差很大,您可能希望将其分解为更小的函数。跨越超过一屏文本的条件块很难阅读。

没有适用于每一种语言的严格规则。像只有一个return语句这样的东西不会使你的代码好。但是好的代码将允许您以这种方式编写函数。