在Ruby中遇到了一个奇怪的行为。不知道它是否只是我。我在ruby 2.3.3上。这是日志。按顺序操作它们,你应该能够重现它。
[1] pry(main)> a &&= nil.a
=> nil
[2] pry(main)> a &&= 1.to_s
=> nil
[3] pry(main)> a = 1 && 1.to_s
=> "1"
[4] pry(main)> a &&= 1.to_s
=> "1"
[5] pry(main)> a &&= nil.a
NoMethodError: undefined method `a' for nil:NilClass
from (pry):5:in `__pry__'
修改
有一个similar question on SO。还有blog post试图解释它。但我不认为他们会解释它。
在SO thread中,它说&&=
是x = x && y if x
的快捷方式。但请考虑一下:
num = 1
a &&= num.to_s
# => nil
VS
num = 1
a = num && num.to_s if num
# => "1"
如果未定义a
,则在红宝石中,a = a
会为您提供nil
。 x = x && y if x
本身就是一个奇怪的操作。
x = x && y if x
这应该与下面相同
if x
x = x && y
end
但这会引发错误,因为未定义x
。那么哪个部分首先被评估?是x = x && y
还是if x
?
答案 0 :(得分:8)
值得注意的是,下面的Stefan提到的一些事情,关于&&=
的属性:
nil
的值。a
逻辑上为真,或者更具体地说,a
不是nil
或false
之一时,才会评估右侧的字词。< / LI>
a
在逻辑上不正确,那么右侧只需要语法上有效,因为它不会被评估。这意味着像nil.a
这样的破解代码在这些特定条件下是可以接受的,它会被解析但是会被忽略。a
为nil
或false
,则a
的值不会更改。 a &&= b
的长格式版本实际上是:
a = if (a)
b
else
a
end
b
可以是任何表达式,包括a &&= b &&= c
至于你的例子,这与表达式的右侧是否得到评估有关。在第一种情况下,a
未定义,因此它不会成为。
稍后当您实际将a
定义为某个内容时,它必须执行右侧,因此您最终会评估nil.a
并且它会爆炸。
在这种情况下,您可以执行任何操作:
nil && whatever(this!, will!, not!, ever!, run!)
它不是片状的,它只是表现得不像你想象的那样。 &&
是短路评估的其中一项内容。那是在:
a && b && c && d
实际解释是:
if a
if b
if c
d
end
end
end
因此,在这种表述中,显而易见的是,如果这些条件中的任何一个失败,它就会挽救并跳过其余条件。
需要注意的一点是a
会自动使用&&=
弹出:
local_variables
# => [:_]
a &&= true
# => nil
local_variables
# => [:a,:_]
&&
并非如此。