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

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


当前回答

作为嵌套if的替代方法,有一种使用do/while(false)在任何地方爆发的方法:

    function()
    {
        HRESULT error = S_OK;

        do
        {
            if(!SUCCEEDED(Operation1()))
            {
                error = OPERATION1FAILED;
                break;
            }

            if(!SUCCEEDED(Operation2()))
            {
                error = OPERATION2FAILED;
                break;
            }

            if(!SUCCEEDED(Operation3()))
            {
                error = OPERATION3FAILED;
                break;
            }
            if(!SUCCEEDED(Operation4()))
            {
                error = OPERATION4FAILED;
                break;
            }
        } while (false);

        return error;
    }

这为您提供了一个出口点,允许您进行其他嵌套操作,但仍然不是真正的深层结构。如果你不喜欢成功,你可以做任何失败的事情。这类事情还允许您在任意两个其他检查之间添加其他代码,而无需重新缩进任何内容。

如果你真的疯了,整个If块也可以宏化。: D

    #define BREAKIFFAILED(x,y) if (!SUCCEEDED((x))) { error = (Y); break; }

    do
    {
        BREAKIFFAILED(Operation1(), OPERATION1FAILED)
        BREAKIFFAILED(Operation2(), OPERATION2FAILED)
        BREAKIFFAILED(Operation3(), OPERATION3FAILED)
        BREAKIFFAILED(Operation4(), OPERATION4FAILED)
    } while (false);

其他回答

I've seen it in coding standards for C++ that were a hang-over from C, as if you don't have RAII or other automatic memory management then you have to clean up for each return, which either means cut-and-paste of the clean-up or a goto (logically the same as 'finally' in managed languages), both of which are considered bad form. If your practices are to use smart pointers and collections in C++ or another automatic memory system, then there isn't a strong reason for it, and it become all about readability, and more of a judgement call.

Structured programming says you should only ever have one return statement per function. This is to limit the complexity. Many people such as Martin Fowler argue that it is simpler to write functions with multiple return statements. He presents this argument in the classic refactoring book he wrote. This works well if you follow his other advice and write small functions. I agree with this point of view and only strict structured programming purists adhere to single return statements per function.

你知道有句谚语——情人眼里出西施。

有些人信得过NetBeans,有些人信得过IntelliJ IDEA,有些人信得过Python,有些人信得过PHP。

在一些商店,如果你坚持这样做,你可能会丢掉工作:

public void hello()
{
   if (....)
   {
      ....
   }
}

这个问题完全是关于可见性和可维护性。

I am addicted to using boolean algebra to reduce and simplify logic and use of state machines. However, there were past colleagues who believed my employ of "mathematical techniques" in coding is unsuitable, because it would not be visible and maintainable. And that would be a bad practice. Sorry people, the techniques I employ is very visible and maintainable to me - because when I return to the code six months later, I would understand the code clearly rather seeing a mess of proverbial spaghetti.

嘿,伙计(就像一个前客户曾经说过的),做你想做的,只要你知道如何在我需要你解决它的时候解决它。

I remember 20 years ago, a colleague of mine was fired for employing what today would be called agile development strategy. He had a meticulous incremental plan. But his manager was yelling at him "You can't incrementally release features to users! You must stick with the waterfall." His response to the manager was that incremental development would be more precise to customer's needs. He believed in developing for the customers needs, but the manager believed in coding to "customer's requirement".

我们经常因为打破数据规范化、MVP和MVC边界而感到内疚。我们内联而不是构造函数。我们走捷径。

就我个人而言,我认为PHP是一种糟糕的实践,但我又知道什么呢?所有的理论争论都归结为试图满足一套规则

质量=精度,可维护性 和盈利能力。

所有其他规则都退居幕后。当然,这条规则永远不会消失:

懒惰是一种美德 程序员。

我倾向于单一退出,除非事情真的变得复杂。我发现在某些情况下,多个存在点可以掩盖其他更重要的设计问题:

public void DoStuff(Foo foo)
{
    if (foo == null) return;
}

在看到这段代码时,我马上会问:

'foo'是否为空? 如果是这样,有多少客户端'DoStuff'曾经调用一个空'foo'函数?

根据这些问题的答案,可能是这样

这种检查毫无意义,因为它从来都不是真的。它应该是一个断言) 这种检查很少是正确的,所以最好改变那些特定的调用函数,因为它们可能应该采取一些其他的操作。

在上述两种情况下,代码可能都可以用断言重做,以确保'foo'永远不为空,并更改相关的调用者。

还有另外两个原因(我认为是针对c++代码的),多重存在实际上会产生负面影响。它们是代码大小和编译器优化。

在函数出口作用域中的非pod c++对象将调用其析构函数。如果有几个return语句,那么作用域中可能有不同的对象,因此要调用的析构函数列表也会不同。因此,编译器需要为每个return语句生成代码:

void foo (int i, int j) {
  A a;
  if (i > 0) {
     B b;
     return ;   // Call dtor for 'b' followed by 'a'
  }
  if (i == j) {
     C c;
     B b;
     return ;   // Call dtor for 'b', 'c' and then 'a'
  }
  return 'a'    // Call dtor for 'a'
}

如果代码大小是一个问题,那么这可能是值得避免的。

另一个问题涉及到“命名返回值优化”(又名复制省略,ISO c++ '03 12.8/15)。c++允许实现在可以的情况下跳过调用复制构造函数:

A foo () {
  A a1;
  // do something
  return a1;
}

void bar () {
  A a2 ( foo() );
}

就像代码一样,对象'a1'是在'foo'中构造的,然后它的复制构造将被调用来构造'a2'。然而,复制省略允许编译器在堆栈上与'a2'相同的位置构造'a1'。因此,当函数返回时,不需要“复制”对象。

多个出口点会使编译器的检测工作复杂化,至少对于相对较新的vc++版本,优化不会发生在函数体有多个返回的地方。有关详细信息,请参阅Visual c++ 2005中的命名返回值优化。

Well, maybe I'm one of the few people here old enough to remember one of the big reasons why "only one return statement" was pushed so hard. It's so the compiler can emit more efficient code. For each function call, the compiler typically pushes some registers on the stack to preserve their values. This way, the function can use those registers for temporary storage. When the function returns, those saved registers have to be popped off the stack and back into the registers. That's one POP (or MOV -(SP),Rn) instruction per register. If you have a bunch of return statements, then either each one has to pop all the registers (which makes the compiled code bigger) or the compiler has to keep track of which registers might have been modified and only pop those (decreasing code size, but increasing compilation time).

今天仍然坚持使用一个return语句的一个原因是易于自动重构。如果您的IDE支持方法提取重构(选择一系列行并将它们转换为一个方法),那么如果您想提取的行中有一个return语句,特别是如果您正在返回一个值,则很难做到这一点。