为什么函数只有一个退出点?

时间:2011-01-29 19:02:04

标签: coding-style

我一直听说单个退出点功能是一种糟糕的代码方式,因为你失去了可读性和效率。我从来没有听到任何人争辩对方。

我认为这与CS有关,但这个问题在cstheory stackexchange中被击落。

7 个答案:

答案 0 :(得分:99)

有不同的思想流派,主要归结为个人偏好。

一个是如果只有一个退出点,那就不那么容易混淆了 - 你有一条通过这个方法的路径,你知道在哪里寻找出口。在负面,如果使用缩进来表示嵌套,则代码会向右大量缩进,并且跟随所有嵌套作用域变得非常困难。

另一个是你可以检查前置条件并在方法开始时提前退出,这样你就可以在方法体中知道某些条件是真的,而不是整个方法体缩进5英里到对。这通常可以最大限度地减少您需要担心的范围数量,从而使代码更容易理解。

第三是您可以随意退出。在过去,这曾经更加令人困惑,但现在我们有语法着色编辑器和编译器来检测无法访问的代码,因此处理起来要容易得多。

我正好在中间营地。执行单个退出点是一种毫无意义甚至适得其反的限制恕我直言,而随机退出一个方法有时会导致混乱难以遵循逻辑,在那里很难看出给定的代码是否会或将不会执行。但是“选通”你的方法可以大大简化方法的主体。

答案 1 :(得分:34)

我的一般建议是,在可行的情况下,返回语句应位于具有任何副作用的第一个代码之前,或者位于具有任何副作用的最后一个代码之后。我会考虑这样的事情:

  if (!argument)  // Check if non-null
    return ERR_NULL_ARGUMENT;
  ... process non-null argument
  if (ok)
    return 0;
  else
    return ERR_NOT_OK;

更清晰:

  int return_value;
  if (argument) // Non-null
  {
    .. process non-null argument
    .. set result appropriately
  }
  else
    result = ERR_NULL_ARGUMENT;
  return result;

如果某个条件应该阻止某个函数做任何事情,我更喜欢在函数执行任何操作的点之上的某个位置提前返回函数。但是,一旦该功能采取了具有副作用的行动,我宁愿从底部返回,以明确必须处理所有副作用。

答案 2 :(得分:16)

如果您觉得某个功能需要多个退出点,则该功能太大而且功能太多。

我建议阅读Robert C. Martin的书“清洁代码”中有关函数的章节。

基本上,你应该尝试使用4行或更少的代码编写函数。

来自Mike Long’s Blog的一些说明:

  • 功能的第一条规则:它们应该很小
  • 功能的第二条规则:它们应小于
  • if语句中的块,while语句,for循环等应该是一行
  • ...那行代码通常是函数调用
  • 应该有不超过一个或两个级别的缩进
  • 功能应该做一件事
  • 函数语句应该都处于相同的抽象级别
  • 一个函数不应超过3个参数
  • 输出参数是代码气味
  • 将布尔标志传递给函数真的很糟糕。根据定义,您可以在函数中执行两次操作。
  • 副作用是谎言。

答案 3 :(得分:14)

单一进入和退出点是结构化编程的原始概念与逐步的Spaghetti Coding。有一种观点认为,多个退出点函数需要更多代码,因为您必须正确清理为变量分配的内存空间。考虑一个场景,其中函数分配变量(资源)并且提前退出函数并且没有适当的清理会导致资源泄漏。此外,在每次退出之前构建清理会产生大量冗余代码。

答案 4 :(得分:14)

对于大多数事情,它都归结为可交付成果的需求。在“过去的日子”中,带有多个返回点的意大利面条代码会引起内存泄漏,因为喜欢该方法的编码器通常不能很好地清理。在从嵌套范围返回的情况下,当返回期间弹出堆栈时,某些编译器还“丢失”对返回变量的引用也存在问题。更普遍的问题是重入代码,它试图使函数的调用状态与其返回状态完全相同。 oop的变种人违反了这一点,这个概念被搁置了。

有可交付成果,尤其是内核,需要多个出口点提供的速度。这些环境通常具有自己的内存和进程管理,因此泄漏的风险最小化。

就个人而言,我喜欢单点退出,因为我经常使用它在return语句中插入断点并执行代码检查代码如何确定该解决方案。我可以进入入口并逐步完成,我使用广泛的嵌套和递归解决方案。作为代码审阅者,函数中的多个返回需要更深入的分析 - 所以如果你这样做是为了加快实现,那么你就是在抢劫彼得以拯救保罗。代码审查需要更多时间,使有效实施的假设无效。

- 2美分

有关详细信息,请参阅此文档:NISTIR 5459

答案 5 :(得分:4)

在我看来,仅在一点退出函数(或其他控制结构)的建议通常是超卖的。通常有两个原因只能在一点退出:

  1. 单退出代码应该更容易阅读和调试。 (我承认我没有考虑到这个原因,但是给出了它。更容易阅读和调试的是单<条目代码。)
  2. 单退出代码链接并更清晰地返回。
  3. 第二个原因是微妙的并且有一些优点,特别是如果函数返回一个大的数据结构。但是,我不会太担心,除了......

    如果是学生,您希望在课堂上获得最高分。做教练喜欢的。从他的角度来看,他可能有充分的理由;所以,至少,你会了解他的观点。这本身就有价值。

    祝你好运。

答案 6 :(得分:3)

I used to be an advocate of single-exit style. My reasoning came mostly from pain...

Single-exit is easier to debug.

Given the techniques and tools we have today, this is a far less reasonable position to take as unit tests and logging can make single-exit unnecessary. That said, when you need to watch code execute in a debugger, it was much harder to understand and work with code containing multiple exit points.

This became especially true when you needed to interject assignments in order to examine state (replaced with watch expressions in modern debuggers). It was also too easy to alter the control flow in ways that hid the problem or broke the execution altogether.

Single-exit methods were easier to step through in the debugger, and easier to tease apart without breaking the logic.