【问题标题】:Ruby's if / else in methodsRuby 的 if / else 方法
【发布时间】:2018-03-29 12:17:50
【问题描述】:

编辑:我收到了有关重构为三元运算的答案。虽然我知道以下所有语言都可以做到这一点,但这并不一定是我最初关于风格的问题的意图。我已经编辑了 sn-ps 以反映这一点。


我很好奇在方法中使用if/else 时总是使用else 是惯用还是首选。

例如,在 JS 中,这在风格上是可以接受的 (and sometimes preferred)

function jsFunc(x) {
  if (x == 0) {
    // do a bunch of stuff here
    return answer;
  }

  // do something else
  return differentAnswer;
}

我在 Python 中也看到过类似的风格:

def py_func(x):
    if x == 0:
        # do a bunch of stuff here
        return answer
    # do something here
    return differentAnswer

但从我看到的 Ruby 来看,它总是:

def ruby_method(x)
  if x == 0
    # do a bunch of stuff here
    answer
  else
    # do something else
    differentAnswer
  end
end

我还收到了一条评论,说在 Ruby 中不使用 else 似乎更麻烦。 Rubyists 更喜欢显式的else 吗? (也很好奇很多语言是隐含的。)

【问题讨论】:

  • [免责声明:固执己见,但仍然正确] Ruby 主义者根本不喜欢使用 if/else 条件,因为它已经带来了太多混乱。
  • 您提供的示例不适用于该问题,因为它可以用多种语言写成return x == 0 ? "Yes" : "No"。您应该在 if 语句的两个分支上添加一些代码以使问题相关。
  • 来自 Martin Fowler 的书 Refactoring: Improving the Design of Existing Code(还有一个 Ruby Edition):“用保护子句替换嵌套条件的关键点是重点之一。如果您使用的是 if- then-else 构造,您对 if 腿和 else 腿赋予相同的权重。这向读者传达了这两条腿的可能性和重要性相同。相反,保护子句说:“这种情况很少见,如果发生了,做点什么然后出去。”“
  • @Stefan 谢谢。那么,我认为对我来说令人困惑的是,在我见过的 JS 和 Py 风格/linter 指南中,没有办法“向读者传达腿同样可能和重要”我>。 else 返回被认为是不必要的(JSPy)。
  • 您所指的规则(例如no-else-return)是关于使用else return 之后,它们不是关于一般禁止else。因此,一个简单且对 linter 友好的解决方法是将结果分配给一个变量并在 if-else 块之后返回该变量。

标签: ruby if-statement coding-style


【解决方案1】:

这实际上取决于。

Guard 子句returns 实际上在 Ruby 中经常使用。他们甚至受到the widely accepted style guide 的鼓励。

但是,保护子句用于极端情况。所以你必须问自己x 的可能值是多少,实际上0 的频率是多少?


如果它很少使用 0 并且有点特别,那么开头的 return 是完全可以接受的(并鼓励)。

例如,这是一个完全可用(尽管不是最佳)的阶乘实现:

def factorial(n)
  return 1 if n.zero?

  n * factorial(n.pred)
end

原因是0 绝对是一个极端案例。


另一方面,如果'Yes''No' 情况既可能又正常,则应在代码中直观地表示这种对称性(if - else)。

例如,考虑一个机器人决定在红绿灯上做什么:

def take_action(light)
  if light.green?
    go
  elsif light.yellow?
    prepare_to_go
  elsif light.red?
    wait
  end
end

您可以使用保护子句来编写它,但这听起来很奇怪。所有可能的颜色都是“主”颜色。


无论哪种方式,在这种特定情况下都有一个更简洁的替代方案:

x.zero? ? 'Yes' : 'No' 

【讨论】:

  • 感谢您的详尽回答。我认为我的部分好奇心也与我所看到的 JS 和 py 代码中缺少明确的 else 返回的事实有关,因为它们被视为unnecessary。对我来说,这与使用保护子句仍然有些不同(至少意图似乎不同),即使结果可能相同,具体取决于实现。 – jtanadi 5 分钟前
  • @jtanadi Ruby 对所有方法都有一个隐式返回,与其他方法(如 JavaScript)相比,这里有些偏斜。 Ruby 的if 也返回执行分支的结果。与其他语言做同样的事情相比,这些结合起来可以产生一些非常少的代码。
【解决方案2】:

我认为这是因为在 Ruby 中我们有隐式返回,而 Ruby 开发人员往往不喜欢使用 return。实际上,您的 sn-p 的替代方案是

def ruby_method(x)
  return "Yes" if x.zero?
  "No"
end

我觉得有点奇怪

【讨论】:

  • {true => "Yes", false => "No"}[x == 0] :)
  • 很酷,但这很奇怪:D
  • @mudasobwa x.zero? ? "Yes" : "No"
  • %w[Yes No].public_send((x == 0 ? "fir" : "la") << "st")
  • 这么多奇怪的方法来做一个简单的 if/else 返回。但这就是我喜欢它的原因。 :)
猜你喜欢
  • 1970-01-01
  • 2017-01-10
  • 1970-01-01
  • 2013-05-18
  • 2012-10-03
  • 2011-01-07
  • 2011-12-15
  • 2016-05-18
  • 2018-04-21
相关资源
最近更新 更多