是否比if语句更优雅的函数返回?

时间:2008-12-10 10:54:22

标签: if-statement return

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

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);

        }

14 个答案:

答案 0 :(得分:40)

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

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

  

最少使用控制

     
      
  1. 使用专门的最小化条件的使用   构造这样的三元化,   继承,以及类等类   默认值,类一次和类   分离器
  2.   
  3. 使用早期return简化条件。
  4.   
  5. 通过使用动作应用程序最大限度地减少循环结构的使用   Class Separate和Class等类   类FileSystemVisitor。
  6.   
  7. 通过早期退出简化迭代逻辑(通过return,   continuebreak语句。
  8.   

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

答案 1 :(得分:17)

这是可以违反规则(即最佳实践)的情况之一。通常,您希望函数中的返回点尽可能少。实际的原因是它简化了对代码的读取,因为您可以始终假设每个函数都将获取其参数,执行其逻辑并返回其结果。为各种情况提供额外的回报往往会使逻辑变得复杂,并增加了阅读和完全理解代码所需的时间。一旦你的代码到达维护阶段,那么多个返回会对新程序员的生产力产生巨大影响,因为他们试图破译逻辑(当评论稀疏且代码不清楚时,它尤其糟糕)。该问题相对于函数的长度呈指数增长。

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

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

答案 2 :(得分:11)

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

我尽量避免身体中间的早期回归。有时它们是最好的方式,但大多数时候我认为它们很复杂。

此外,作为一般规则,我尝试最小化嵌套控制结构。显然你可以把这个拿得太远,所以你必须谨慎使用。将嵌套if转换为单个switch / case对我来说更加清晰,即使谓词重复了一些子表达式(并且假设这不是一个语言中的性能关键循环,对于子表达式消除来说太愚蠢)。特别是我不喜欢长函数/方法体中嵌套ifs的组合,因为如果由于某种原因跳到代码的中间,你最终会向上和向下滚动以精神重建给定行的上下文。

答案 3 :(得分:4)

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

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

因此,当我查看一个不熟悉的函数时,我要做的第一件事就是查找所有return s。真正有用的是设置语法着色以使return具有与其他任何颜色不同的颜色。 (我选择红色。)这样,return成为确定函数功能的有用工具,而不是为不警情的人隐藏绊脚石。

答案 4 :(得分:1)

啊是监护人。

Imho,是的 - 它的逻辑更清晰,因为返回是明确的并且恰好在条件旁边,它可以很好地与类似的结构分组。当“return”被“throw new Exception”替换时,这更加适用。

答案 5 :(得分:1)

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

它还使代码更具说明性,因为这是你将它描述给另一个人的方式,所以开发人员可能非常接近理解它。

如果稍后函数的复杂性增加,并且你有很好的测试,你可以简单地将每个替代项包装在一个新函数中,并在case分支中调用它们,这样你就可以保留声明式样式。

答案 6 :(得分:0)

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

然而,这是分裂最好的头发。我相信你必须担心更大的问题:)

答案 7 :(得分:0)

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

所以,如果你确定,没有别的选择2,但如果可能有其他条件的范围,那么我更喜欢选项1

答案 8 :(得分:0)

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

这样的例外
  if (a) {
    return x;
  }
  return y;

因为语言的工作方式,但总的来说,最好只有尽可能少的退出点。

答案 9 :(得分:0)

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

但是,如果方法简短易读,我不介意在方法中间返回。如果方法很大,在我看来,它已经不是很易读,所以它将被重构为具有内联返回的多个函数,或者我将在结尾处通过单个返回显式地从控制结构中断。

答案 10 :(得分:0)

我很想把它关闭,因为我已经看到了一些类似的线程,包括Invert “if” statement to reduce nesting,它有很好的答案。

我现在就让它活着...... ^ _ ^

为了得到答案,我相信早期作为保护条款的回归比深度嵌套的if更好。

答案 11 :(得分:0)

我已经看过两种类型的代码,我更喜欢第一种代码,因为它看起来很容易阅读并且对我来说是可以理解的,但是我已经读过许多早期存在的地方是更好的方法。

答案 12 :(得分:0)

至少有另一种选择。将实际工作的细节与是否执行工作的决定分开。如下所示:

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);

    }

这三个中的任何一个(你的两个加上上面的第三个)对于小到这个小的情况是合理的。然而,拥有数百行的功能并且在整个过程中散布着多个“纾困点”将是一件坏事。

答案 13 :(得分:0)

多年来,我一直在用自己的代码进行辩论。我开始倾向于一次回归并慢慢失效。

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

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