如果||优先级高于=,那为什么`a || a = b`工作?

时间:2013-02-03 16:56:58

标签: ruby

我理解||or&&and之间的区别,但我不明白的是:

考虑一种方法,该方法返回@var的值,或者如果@var为零,则初始化它。

当我来自JavaScript背景时,我会这样写,因为||的优先级高于=

def some_method
  @var || (@var = MyClass.new)
end

或使用or,因为or的优先级较低:

def some_method
  @var or @var = MyClass.new
end

或更简洁:

def some_method
  @var ||= MyClass.new
end

但碰巧这个版本也有效

def some_method
  @var || @var = MyClass.new
end

我在网上搜索但没有找到有用的结果。

其中大多数只是告诉||or之间的区别。

运算符优先级表清楚地表明||的优先级高于=

我甚至可以a = b || c = d,Ruby将其视为a = (b || (c = d))

这种行为是在某处记录的还是Ruby中的某种魔力?

P.S。 CoffeeScript也有相同的行为。

更新/澄清:这个问题与短路评估无关。但关于运营商优先权。请让我再说一遍:

如果||的优先级高于=,那么为什么ruby将a || a = b视为a || (a = b),而不是(a || a) = b,并引发语法错误?< / p>

3 个答案:

答案 0 :(得分:3)

Ruby使用所谓的short-circuit evaluation来评估这些逻辑表达式。只有当第一个参数不足以评估表达式时,才会考虑第二个参数。

在您的示例中,由于@var最初为nil,因此会计算表达式的后半部分,并将其设置为MyClass.new的实例。

这些表达式的扩展非常有趣。有一些博文herehere很好地涵盖了它。

答案 1 :(得分:2)

只有在表达式中存在歧义时,优先级才会成为问题。如果:

 @var || @var = MyClass.new

没有歧义。赋值运算符=只有在其左侧有一个变量时才有意义(忽略多次赋值产生的复杂性)。将某些内容分配给名为“@var || @var”的变量没有意义。因此,没有歧义。解释上述表达式的唯一方法是将其解释为:

 @var || (@var = MyClass.new)

因此,优先权不是问题。

答案 2 :(得分:0)

我会完全忘记andor。如果需要,只需使用&&||括号。

您的上一个示例仅适用,因为您正在使用实例变量。考虑一下这里的区别:

1.9.3> newvar
NameError: undefined local variable or method `newvar' for main:Object
        from (irb):59
        from /home/don/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'
1.9.3> @newvar
 => nil

如果您尝试newvar || newvar = 3,则会引发错误。

您可能想看看这个问题:What does ||= (or-equals) mean in Ruby?