是否有充分的理由说明在函数中只有一个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。大多数非最终回报可能是例外。

简而言之,

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

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

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

如果可以只写下一个观点,那就是我的观点:

我完全不同意“单返回语句理论”,认为它在代码可读性、逻辑和描述方面都是推测性的,甚至是破坏性的。

使用一次-一次返回的习惯对于纯过程式编程来说都很糟糕,更不用说更高级的抽象(函数式、组合式等)了。此外,我希望所有以这种风格编写的代码都经过一些特殊的重写解析器,使其具有多个返回语句!

一个函数(如果它真的是一个函数/查询,根据“查询-命令分离”注意-见埃菲尔编程语言。例如)必须定义与控制流场景一样多的返回点。它在数学上更加清晰和一致;它是编写函数(即查询)的方法。

但对于你的特工收到的突变信息——程序调用,我不会那么激进。

我相信多次返回通常是好的(在我用c#编写的代码中)。单返回样式是从C语言中保留下来的,但是您可能没有用C语言编写代码。

在所有编程语言中,没有法律要求一个方法只有一个退出点。有些人坚持这种风格的优越性,有时他们把它提升为“规则”或“法律”,但这种信念没有任何证据或研究支持。

在C代码中,多个返回样式可能是一个坏习惯,资源必须显式地去分配,但Java、c#、Python或JavaScript等语言具有自动垃圾收集和try. finally块(以及在c#中使用块)等构造,并且这个参数不适用-在这些语言中,需要集中的手动资源回收是非常罕见的。

在某些情况下,单个返回值可读性更好,而在某些情况下则不是这样。看看它是否减少了代码行数,使逻辑更清晰,或减少了大括号、缩进或临时变量的数量。

因此,根据你的艺术感受使用尽可能多的返回,因为这是一个布局和可读性问题,而不是技术问题。

我在我的博客上详细地讨论过这个问题。

作为指导原则,我投票支持单次返回。这有助于一个常见的代码清理处理…例如,看看下面的代码…

void ProcessMyFile (char *szFileName)
{
   FILE *fp = NULL;
   char *pbyBuffer = NULL:

   do {

      fp = fopen (szFileName, "r");

      if (NULL == fp) {

         break;
      }

      pbyBuffer = malloc (__SOME__SIZE___);

      if (NULL == pbyBuffer) {

         break;
      }

      /*** Do some processing with file ***/

   } while (0);

   if (pbyBuffer) {

      free (pbyBuffer);
   }

   if (fp) {

      fclose (fp);
   }
}