下面的代码在Ruby中是什么意思?

||=

它的语法有什么意义或原因吗?


当前回答

irb(main):001:0> a = 1
=> 1
irb(main):002:0> a ||= 2
=> 1

因为a已经被设为1了

irb(main):003:0> a = nil
=> nil
irb(main):004:0> a ||= 2
=> 2

因为a是nil

其他回答

如果X没有值,它将被赋值为y,否则,它将保留它的原始值,在本例中为5:

irb(main):020:0> x = 5
=> 5
irb(main):021:0> y = 10
=> 10
irb(main):022:0> x ||= y
=> 5

# Now set x to nil. 

irb(main):025:0> x = nil
=> nil
irb(main):026:0> x ||= y
=> 10

A ||= b和A = b是一样的如果A。nil?或者a = b,除非a

但是所有3个选项都能显示相同的性能吗?在Ruby 2.5.1中

1000000.times do
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
  a ||= 1
end

在我的电脑上花费0.099秒,而

1000000.times do
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
  a = 1 unless a
end

用时0.062秒。这几乎快了40%。

然后我们还有:

1000000.times do
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
  a = 1 if a.nil?
end

这需要0.166秒。

并不是说这将在一般情况下产生重大的性能影响,但是如果您确实需要最后一点优化,那么可以考虑这个结果。 顺便说一下:a = 1,除非a对新手来说更容易理解,否则它是不言自明的。

注1:重复分配行多次的原因是为了减少循环在测量时间上的开销。

注2:如果我在每次赋值前执行a=nil,结果是类似的。

irb(main):001:0> a = 1
=> 1
irb(main):002:0> a ||= 2
=> 1

因为a已经被设为1了

irb(main):003:0> a = nil
=> nil
irb(main):004:0> a ||= 2
=> 2

因为a是nil

这个问题在Ruby邮件列表和Ruby博客上讨论得如此频繁,以至于现在Ruby邮件列表上甚至有一些线程,它们的唯一目的就是收集到Ruby邮件列表上讨论这个问题的所有其他线程的链接。

这里有一个:||= (OR Equal)线程和页面的最终列表

如果你真的想知道发生了什么,可以看看Ruby语言规范草案的第11.4.2.3节“缩写赋值”。

作为第一近似,

a ||= b

等于

a || a = b

并不等同于

a = a || b

然而,这只是一种近似,特别是在a未定义的情况下。根据是简单的变量赋值、方法赋值还是索引赋值,语义也有所不同:

a    ||= b
a.c  ||= b
a[c] ||= b

都有不同的待遇。

a ||= b

等于

a || a = b

而不是

a = a || b

因为您使用默认值定义哈希(对于任何未定义的键,哈希将返回默认值)

a = Hash.new(true) #Which is: {}

如果你使用:

a[10] ||= 10 #same as a[10] || a[10] = 10

A仍然是:

{}

但如果你这样写

a[10] = a[10] || 10

一个变成了:

{10 => true}

因为你已经在键10处赋值了它自己的值,默认为true,所以现在哈希是为键10定义的,而不是一开始就不执行赋值。