是否有充分的理由说明在函数中只有一个return语句是一个更好的实践?
或者在逻辑上正确的情况下,可以从函数中返回,这意味着函数中可能有许多返回语句?
是否有充分的理由说明在函数中只有一个return语句是一个更好的实践?
或者在逻辑上正确的情况下,可以从函数中返回,这意味着函数中可能有许多返回语句?
当前回答
我目前正在开发一个代码库,其中有两个人盲目地赞同“单点退出”理论,我可以告诉你,从经验来看,这是一个非常可怕的实践。这使得代码极其难以维护,我将向您展示原因。
根据“单点退出”理论,你不可避免地会得到这样的代码:
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条件和大括号都正确匹配。
这种方法使代码维护极其困难,而且容易出错。
其他回答
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语句,特别是如果您正在返回一个值,则很难做到这一点。
我经常在一个方法的开头有几个语句来返回“简单”的情况。例如,这个:
public void DoStuff(Foo foo)
{
if (foo != null)
{
...
}
}
... (恕我直言)可以像这样变得更具可读性:
public void DoStuff(Foo foo)
{
if (foo == null) return;
...
}
所以,是的,我认为从一个函数/方法中有多个“出口点”是很好的。
函数中return语句越多,该方法的复杂性就越高。如果您发现自己想知道是否有太多的return语句,那么您可能需要问问自己,该函数中是否有太多的代码行。
但是,不是,一个/多个返回语句并没有错。在某些语言中,这是一种比其他语言(C)更好的实践(c++)。
我使用多个出口点使错误情况+处理+返回值尽可能接近。
所以必须测试条件a, b, c必须为真,你需要用不同的方式处理它们:
if (a is false) {
handle this situation (eg. report, log, message, etc.)
return some-err-code
}
if (b is false) {
handle this situation
return other-err-code
}
if (c is false) {
handle this situation
return yet-another-err-code
}
perform any action assured that a, b and c are ok.
a, b和c可能是不同的东西,比如a是输入参数检查,b是新分配内存的指针检查,c是检查参数a中的值。
使用单一出口点可以降低圈复杂度,因此,从理论上讲,可以降低在修改代码时引入错误的可能性。然而,实践往往表明需要更务实的方法。因此,我倾向于只有一个出口点,但如果可读性更好,允许我的代码有多个出口点。