在ruby&& =运算符是片状?

时间:2017-12-13 23:17:03

标签: ruby

在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__'

查看1和[5],以及2和[4]

修改

有一个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会为您提供nilx = x && y if x本身就是一个奇怪的操作。

x = x && y if x

这应该与下面相同

if x
  x = x && y
end

但这会引发错误,因为未定义x。那么哪个部分首先被评估?是x = x && y还是if x

1 个答案:

答案 0 :(得分:8)

值得注意的是,下面的Stefan提到的一些事情,关于&&=的属性:

  • 左侧的变量始终被视为已定义,无论是否实际进行了分配。
  • 如果未明确指定值,则已定义的变量将假定nil的值。
  • 只有在a逻辑上为真,或者更具体地说,a不是nilfalse之一时,才会评估右侧的字词。< / LI>
  • 因此,如果a在逻辑上不正确,那么右侧只需要语法上有效,因为它不会被评估。这意味着像nil.a这样的破解代码在这些特定条件下是可以接受的,它会被解析但是会被忽略。
  • 如果anilfalse,则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,:_]

&&并非如此。