为什么`在Ruby中返回a或b`是一个void值表达式错误?

Why is `return a or b` a void value expression error in Ruby?

这很好:

1
2
3
def foo
  a or b
end

这也很好:

1
2
3
def foo
  return a || b
end

返回void value expression

1
2
3
def foo
  return a or b
end

为什么?它甚至没有被执行;它没有通过语法检查。void value expression是什么意思?


return a or b被解释为(return a) or b,因此return a的值是计算(return a) or b的值所必需的,但由于return从未留下一个值(因为它从该位置逃逸),因此它不被设计为在原始位置返回有效值。因此整个表达保留在(some_void_value) or b中,并被卡住。这就是它的意思。


在我之前问过的一个类似问题中,Stefan在评论中解释说,orand实际上是控制流运算符,不应分别用作布尔运算符(||&&)。

他还引用了一篇文章来解释这些控制流操作符背后的推理:

and and or originate (like so much of Ruby) in Perl. In Perl, they were largely used to modify control flow, similar to the if and unless statement modifiers. (...)

它们提供了以下示例:

and

1
foo = 42 && foo / 2

This will be equivalent to:

1
foo = (42 && foo) / 2 # => NoMethodError: undefined method `/' for nil:NilClass

目标是给foo分配一个数字,并用它一半的值重新分配它。因此,and运算符在这里很有用,因为它的优先级较低,它修改/控制单个表达式的正常流:

1
foo = 42 and foo / 2 # => 21

它还可以作为循环中的反向if语句使用:

1
next if widget = widgets.pop

相当于:

1
widget = widgets.pop and next

or

useful for chaining expressions together

如果第一个表达式失败,则执行第二个表达式,依此类推:

1
foo = get_foo() or raise"Could not find foo!"

它还可以用作:

reversed unless statement modifier:

1
raise"Not ready!" unless ready_to_rock?

相当于:

1
ready_to_rock? or raise"Not ready!"

因此,正如sawa解释的,a or b的表达在:

1
return a or b

优先级低于return a,执行时,该优先级会避开当前上下文,不提供任何值(无效值)。然后触发错误(repl.it执行):

(repl):1: void value expression

1
2
puts return a or b
              ^~

由于Stefan的评论(谢谢),这个答案成为可能。


由于or的优先级比||低,这意味着return a将在or b之前执行,因此无法访问or b