我理解||
和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>
答案 0 :(得分:3)
Ruby使用所谓的short-circuit evaluation
来评估这些逻辑表达式。只有当第一个参数不足以评估表达式时,才会考虑第二个参数。
在您的示例中,由于@var
最初为nil
,因此会计算表达式的后半部分,并将其设置为MyClass.new
的实例。
答案 1 :(得分:2)
只有在表达式中存在歧义时,优先级才会成为问题。如果:
@var || @var = MyClass.new
没有歧义。赋值运算符=
只有在其左侧有一个变量时才有意义(忽略多次赋值产生的复杂性)。将某些内容分配给名为“@var || @var
”的变量没有意义。因此,没有歧义。解释上述表达式的唯一方法是将其解释为:
@var || (@var = MyClass.new)
因此,优先权不是问题。
答案 2 :(得分:0)
我会完全忘记and
和or
。如果需要,只需使用&&
和||
括号。
您的上一个示例仅适用,因为您正在使用实例变量。考虑一下这里的区别:
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?。