从函数中提前返回是不是比 if 语句更优雅?

Posted

技术标签:

【中文标题】从函数中提前返回是不是比 if 语句更优雅?【英文标题】:Is returning early from a function more elegant than an if statement?从函数中提前返回是否比 if 语句更优雅? 【发布时间】:2010-09-26 05:18:45 【问题描述】:

我和一位同事对以下哪个更优雅存在争议。我不会说谁是谁,所以是不偏不倚的。哪个更优雅?

public function set hitZone(target:DisplayObject):void
        
            if(_hitZone != target)
            
                _hitZone.removeEventListener(MouseEvent.ROLL_OVER, onBtOver);
                _hitZone.removeEventListener(MouseEvent.ROLL_OUT, onBtOut);
                _hitZone.removeEventListener(MouseEvent.MOUSE_DOWN, onBtDown);

                _hitZone = target;

                _hitZone.addEventListener(MouseEvent.ROLL_OVER, onBtOver, false, 0, true);
                _hitZone.addEventListener(MouseEvent.ROLL_OUT, onBtOut, false, 0, true);
                _hitZone.addEventListener(MouseEvent.MOUSE_DOWN, onBtDown, false, 0, true);
            
        

...或...

public function set hitZone(target:DisplayObject):void
        
            if(_hitZone == target)return;

            _hitZone.removeEventListener(MouseEvent.ROLL_OVER, onBtOver);
            _hitZone.removeEventListener(MouseEvent.ROLL_OUT, onBtOut);
            _hitZone.removeEventListener(MouseEvent.MOUSE_DOWN, onBtDown);

            _hitZone = target;

            _hitZone.addEventListener(MouseEvent.ROLL_OVER, onBtOver, false, 0, true);
            _hitZone.addEventListener(MouseEvent.ROLL_OUT, onBtOut, false, 0, true);
            _hitZone.addEventListener(MouseEvent.MOUSE_DOWN, onBtDown, false, 0, true);

        

【问题讨论】:

这是重复的。请查看此帖子:***.com/questions/36707/… 这个问题不是重复的,虽然是的,最重要的答案似乎也回答了我的问题 查看我对similar question 的回复。 【参考方案1】:

在大多数情况下,提前返回可以降低复杂性并使代码更具可读性。

这也是Spartan programming中应用的技术之一:

控制的最少使用

    通过使用专门的 构建这样的三元化, 继承和类,如 Class 默认值、Class Once 和 Class 分隔符 使用早期的 return 简化条件。 通过使用动作应用程序,最大限度地减少循环结构的使用 类,如单独的类和 类 FileSystemVisitor。 通过提前退出简化迭代逻辑(通过returncontinuebreak 语句)。

在您的示例中,我会选择选项 2,因为它使代码更具可读性。检查函数参数时,我使用相同的技术。

【讨论】:

浏览过 Spartan 编程链接后,我不得不说我并不完全喜欢我所看到的。几乎没有空格?短变量名?对于没有花括号的循环?嗯... 我同意莱恩。我还没有读过它,但是:没有空格、短变量名、没有花括号的循环——所有我不喜欢的东西。万维网【参考方案2】:

这是可以打破规则(即最佳做法)的情况之一。通常,您希望函数中的返回点尽可能少。这样做的实际原因是它简化了您对代码的阅读,因为您总是可以假设每个函数都会接受它的参数,执行它的逻辑并返回它的结果。为各种情况添加额外的回报往往会使逻辑复杂化,并增加阅读和完全理解代码所需的时间。一旦您的代码进入维护阶段,那么多次返回可能会对新程序员的生产力产生巨大影响,因为他们试图破译逻辑(当 cmets 稀疏且代码不清楚时尤其糟糕)。问题随着函数的长度呈指数增长。

那么为什么在这种情况下每个人都更喜欢选项 2?这是因为您正在设置一个合约,该函数通过验证传入数据或其他可能需要检查的不变量来强制执行。构造验证的最漂亮的语法是检查每个条件,如果条件无效,则立即返回。这样您就不必通过所有检查来维护某种 isValid 布尔值。

总结一下:我们真正关注的是如何编写验证代码,而不是一般逻辑;选项 2 更适合验证代码。

【讨论】:

此答案的第一段应以粗体书写,因为其中的事实是如此真实,不应被忽视。【参考方案3】:

只要将早期返回组织为函数/方法体顶部的块,那么我认为它们比添加另一层嵌套更具可读性。

我尽量避免在身体中间提前返回。有时它们是最好的方法,但大多数时候我认为它们很复杂。

此外,作为一般规则,我会尽量减少嵌套控制结构。显然你可以把这个做得太过分了,所以你必须谨慎行事。将嵌套的 if 转换为单个 switch/case 对我来说要清楚得多,即使谓词重复一些子表达式(并且假设这不是一种语言中的性能关键循环,因为它太愚蠢而无法消除子表达式)。特别是我不喜欢长函数/方法体中嵌套 if 的组合,因为如果你出于某种原因跳到代码中间,你最终会上下滚动以在心理上重构给定行的上下文。

【讨论】:

【参考方案4】:

根据我的经验,在项目中使用早期回报的问题在于,如果项目中的其他人不习惯它们,他们就不会寻找它们。无论是否提前返回 - 如果涉及多个程序员,请确保每个人至少都知道他们的存在。

我个人编写代码以尽快返回,因为延迟返回通常会引入额外的复杂性,例如尝试安全地退出一堆嵌套循环和条件。

所以当我看到一个不熟悉的函数时,我做的第一件事就是寻找所有的returns。真正有帮助的是设置您的语法着色以赋予 return 与其他任何颜色不同的颜色。 (我喜欢红色。)这样,returns 成为确定函数作用的有用工具,而不是粗心大意的人隐藏的绊脚石。

【讨论】:

【参考方案5】:

啊,守护者。

恕我直言,是的 - 它的逻辑更清晰,因为返回是明确的并且紧邻条件,并且可以很好地与相似的结构分组。这更适用于将“return”替换为“throw new Exception”的情况。

【讨论】:

抱歉听起来很无知 - 什么是“监护人”? 您在方法 2 中描述的模式(提前返回)通常被称为“守卫者”或“看门人”,因为它阻止了对方法其余部分的访问 - 您必须通过一个数字在你做任何事情之前的监护人【参考方案6】:

如前所述,提前返回更具可读性,特别是如果函数体很长,您可能会发现在 3 页函数中错误地删除了 (这本身不是很优雅)并尝试编译可能需要几分钟的非自动化调试。

它还使代码更具声明性,因为这是您向其他人描述它的方式,因此开发人员可能足够接近理解它。

如果以后函数的复杂性增加,并且您有良好的测试,您可以简单地将每个备选方案包装在一个新函数中,并在 case 分支中调用它们,这样您就可以保持声明式风格。

【讨论】:

【参考方案7】:

在这种情况下(一个测试,没有 else 子句)我喜欢测试和返回。它清楚地表明,在这种情况下,无需阅读函数的其余部分,无需执行任何操作。

但是,这会让人毛骨悚然。我相信你一定有更大的问题要担心:)

【讨论】:

【参考方案8】:

选项 2 更具可读性,但当可能需要添加 else 时,代码的可管理性会失败。

因此,如果您确定,则选项 2 没有其他选择,但如果可能存在其他条件的范围,那么我更喜欢选项 1

【讨论】:

【参考方案9】:

选项 1 更好,因为您应该在程序中有最少数量的返回点。 也有例外,如

如果一个) 返回 x; 返回 y;

因为语言的工作方式,但总的来说,退出点越少越好。

【讨论】:

为什么? =) 在提问者的示例中,具有多个返回点有助于清除代码。 嗯,有时候你会想“为什么我做了这么多回报,现在我必须关闭每个回报附近的连接”,但这只是意味着你的代码设计得很糟糕。 【参考方案10】:

我更喜欢避免在函数开头立即返回,并尽可能放置限定逻辑以防止在调用之前进入该方法。当然,这取决于方法的目的。

但是,我不介意在方法中间返回,只要方法简短易读。如果方法很大,在我看来,它已经不是很可读了,所以它要么被重构为具有内联返回的多个函数,要么我将显式地打破控制结构,最后只返回一个返回。

【讨论】:

【参考方案11】:

我很想将其作为完全重复的内容关闭,因为我已经看到了一些类似的主题,包括有很好答案的 Invert “if” statement to reduce nesting。

我现在就让它活下去……^_^

为了回答这个问题,我相信作为保护子句的早期返回比深度嵌套的 if 更好。

【讨论】:

【参考方案12】:

我看过这两种类型的代码,我更喜欢第一种,因为它看起来很容易阅读和理解,但我读过很多地方,早期存在是更好的方法。

【讨论】:

【参考方案13】:

至少还有另一种选择。将实际工作的细节与是否执行工作的决定分开。类似于以下内容:

public function setHitZone(target:DisplayObject):void
    
        if(_hitZone != target)
            setHitZoneUnconditionally(target);

    

public function setHitZoneUnconditionally(target:DisplayObject):void
    
        _hitZone.removeEventListener(MouseEvent.ROLL_OVER, onBtOver);
        _hitZone.removeEventListener(MouseEvent.ROLL_OUT, onBtOut);
        _hitZone.removeEventListener(MouseEvent.MOUSE_DOWN, onBtDown);

        _hitZone = target;

        _hitZone.addEventListener(MouseEvent.ROLL_OVER, onBtOver, false, 0, true);
        _hitZone.addEventListener(MouseEvent.ROLL_OUT, onBtOut, false, 0, true);
        _hitZone.addEventListener(MouseEvent.MOUSE_DOWN, onBtDown, false, 0, true);

    

这三个(你的两个加上上面的第三个)中的任何一个对于像这样小的案例都是合理的。但是,如果函数有数百行长,并且到处散布着多个“救助点”,那将是一件坏事。

【讨论】:

【参考方案14】:

多年来,我一直在与自己的代码进行辩论。我开始喜欢一次回归的生活,然后慢慢地消失了。

在这种情况下,我更喜欢选项 2(一次返回),因为我们只讨论由 if() 包装的 7 行代码,没有其他复杂性。它更具可读性和功能性。它从上到下流动。你知道你从顶部开始,在底部结束。

话虽如此,正如其他人所说,如果在开始时有更多的警卫或更复杂的情况,或者如果函数增长,那么我更喜欢选项 1:在开始时立即返回以进行简单的验证。

【讨论】:

以上是关于从函数中提前返回是不是比 if 语句更优雅?的主要内容,如果未能解决你的问题,请参考以下文章

如何让这个 jQuery 函数更优雅?

从 if 语句问题提供函数返回

86.返回类型和return语句

es6之更优雅的条件语句

布尔函数:if 语句或简单返回

if-else 或提前返回 [关闭]