在Ruby中,|| =(or-equals)是什么意思?

col*_*rco 325 ruby operators

以下代码在Ruby中的含义是什么?

||=
Run Code Online (Sandbox Code Playgroud)

它的语法是否有任何意义或原因?

Ste*_*ett 558

a ||= b是一个"条件赋值运算符".它是一种但不完全(*)的简写a.

它表示" 如果b未定义或(aa),则评估b并设置+=为结果 ".

例如:

a ||= nil # => nil
a ||= 0 # => 0
a ||= 2 # => 0

foo = false # => false
foo ||= true # => true
foo ||= false # => true
Run Code Online (Sandbox Code Playgroud)

Ruby的短路评估意味着如果a += b定义并评估为真,则不评估运算符的右侧,并且不进行任务分配.如果a = a + b并且a ||= b都是局部变量,这种区别是不重要的,但如果它们是类的getter/setter方法则很重要.

令人困惑的是,它看起来与其他赋值运算符(例如a || a = b)类似,但表现不同.

a || a = b   翻译成   a

a || a = b   大致翻译为*   NameError

*除非,a ||= b未定义时,a将是NameError,而b设置ab.

进一步阅读:

  • 谢谢你的回答,它更有意义. (49认同)
  • 没有足够的搜索,但仍然不明白为什么你会使用它而不是 a = a || b. 也许只是我个人的意见,但存在这样的细微差别有点荒谬...... (2认同)
  • @dtc,考虑`h = Hash.new(0); h [1] || = 2`.现在考虑两个可能的扩展`h [1] = h [1] || 2` vs`h [1] || h [1] = 2`.两个表达式都计算为"0",但第一个表达式不必要地增加了哈希的大小.也许这就是为什么Matz选择让`|| =`表现得更像第二次扩张.(我基于另一个答案中链接到的一个线程的示例.) (2认同)
  • 仅供参考,`a|| 如果“a”未定义,a = b`会引发“NameError”。`a ||= b` 不会,而是初始化 `a` 并将其设置为 `b`。据我所知,这是两者之间的唯一区别。同样,`a = a || 之间的唯一区别 我知道的 b` 和 `a ||= b` 是,如果 `a=` 是一个方法,那么无论 `a` 返回什么,它都会被调用。另外,据我所知,“a = b except a”和“a ||= b”之间的唯一区别是,如果“a”为真,则该语句的计算结果为“nil”而不是“a”。有很多近似值,但没有完全等效的...... (2认同)

Jör*_*tag 175

这个问题经常在Ruby邮件列表和Ruby博客上讨论过,现在甚至Ruby邮件列表上都有线程,其唯一的目的是收集Ruby邮件列表上讨论这个问题的所有其他线程的链接..

这是一个:|| =(OR Equal)线程和页面的权威列表

如果您真的想知道发生了什么,请查看Ruby语言草案规范的第11.4.2.3节"缩写分配" .

作为第一个近似值,

a ||= b
Run Code Online (Sandbox Code Playgroud)

相当于

a || a = b
Run Code Online (Sandbox Code Playgroud)

并且等同于

a = a || b
Run Code Online (Sandbox Code Playgroud)

但是,这只是第一次近似,特别是如果a未定义的话.语义也有所不同,具体取决于它是简单的变量赋值,方法赋值还是索引赋值:

a    ||= b
a.c  ||= b
a[c] ||= b
Run Code Online (Sandbox Code Playgroud)

都被区别对待.

  • 这是一个非常神秘的非答案.简短的回答似乎是:a || = b表示,如果a未定义,则为其赋值b,否则不管它.(好吧,有细微差别和特殊情况,但这是基本情况.) (300认同)
  • @SteveBennett:我不会说'a = false; a || = true`确实*不*做你的回答说它做了"细微差别". (20认同)
  • 也许这个问题被问了很多次,因为人们一直在回答这个问题已被问过很多次了. (19认同)
  • 有了这个答案很容易理解为什么有多个线程.如果您尝试使用新手帽子搜索此问题的答案,您会注意到所有答案都不清楚.例如,有了这个,你只是在说什么不是.我建议你改善你的答案并给新手一个简单的答案:a = b除非a (6认同)
  • 提供一个尖刻的、连续的、不回答是没有帮助的。如果您认为问题不符合您的要求并且您不想提供简单的答案,那么请不要发布并继续。 (3认同)
  • 第二个链接遭受了一点点腐蚀(来自http://stackoverflow.com/users/540162/nightfirecat的meta评论). (2认同)
  • 根本不是一个好的答案.不知道为什么这被接受了.它几乎没有试图解释`|| =`是什么,而是试图将某人指向另一个线程(这很具有讽刺意味,因为你*试图*结束这个追逐).为什么不直接说它是什么?我相信它会让你和读者更多地工作.Downvoted. (2认同)
  • 非常缺乏答案。你没有解释它的作用 (2认同)
  • 对于 ruby​​ 新手,他们可能不知道 || a = b。最好至少举个例子并说明结果是什么。否则,你只是在介绍另一个问题而不是回答 (2认同)

the*_*ted 32

简洁而完整的答案

a ||= b
Run Code Online (Sandbox Code Playgroud)

评估方式与以下行相同

a || a = b
a ? a : a = b
if a then a else a = b end
Run Code Online (Sandbox Code Playgroud)

-

另一方面,

a = a || b
Run Code Online (Sandbox Code Playgroud)

评估方式与以下行相同

a = a ? a : b
if a then a = a else a = b end
Run Code Online (Sandbox Code Playgroud)

-

编辑:正如AJedi32在评论中指出的那样,这只适用于:1.a是一个已定义的变量.2.评估一次和两次不会导致程序或系统状态的差异.

  • 这不太对.`a || a = b`,`a?a:a = b`,`如果a a else a else a = b end`,`if a a = a else a = b end`如果`a`未定义则会抛出错误,而`a || = b`和`a = a || b`不会.还有,`a || a = b`,`a?a:a = b`,`如果a a else a else a = b end`,`a = a?a:b`,和`if a a = a else a = b end`当`a`是真实时评估`a`两次,而`a || = b`和'a = a || b`不要. (3认同)

vid*_*ang 24

简而言之,a||=b意思是:如果aundefined, nil or false,则分配ba.否则,保持a完整.


nPc*_*omp 16

基本上,


x ||= y 手段

如果x有任何值,请不要更改值,否则设置xy.


Jam*_*low 12

它意味着或等于.它检查左侧的值是否已定义,然后使用它.如果不是,请使用右侧的值.您可以在Rails中使用它来缓存模型中的实例变量.

一个快速的基于Rails的示例,我们创建一个函数来获取当前登录的用户:

class User > ActiveRecord::Base

  def current_user
    @current_user ||= User.find_by_id(session[:user_id])
  end

end
Run Code Online (Sandbox Code Playgroud)

它检查是否设置了@current_user实例变量.如果是,它将返回它,从而保存数据库调用.如果没有设置,我们进行调用,然后将@current_user变量设置为该调用.这是一种非常简单的缓存技术,但是当您在应用程序中多次获取相同的实例变量时非常适合.

  • 这是错的.请阅读http://Ruby-Forum.Com/topic/151660/及其中提供的链接. (8认同)
  • 尽管这个答案可能表现出任何不完整性(不适用于 nil/false),但它是第一个解释您为什么要使用 ||= 的答案,所以谢谢! (2认同)

Kia*_*rom 8

x ||= y
Run Code Online (Sandbox Code Playgroud)

x || x = y
Run Code Online (Sandbox Code Playgroud)

"如果x为false或未定义,则x指向y"


Aje*_*i32 7

准确地说,a ||= b是指"如果a未定义或falsy(falsenil),设置ab和评价(即返回)b,否则计算结果为a".

其他人经常试图说明这a ||= b相当于a || a = ba = a || b.这些等价物有助于理解概念,但要注意它们在所有条件下都不准确.请允许我解释一下:

  • a ||= ba || a = b

    a未定义的局部变量时,这些语句的行为会有所不同.在这种情况下,a ||= b将设置ab(并评估为b),而a || a = b将提高NameError: undefined local variable or method 'a' for main:Object.

  • a ||= ba = a || b

    这些语句的等效常常假设,因为类似的等价是其他真正的简写赋值运算符(即+=,-=,*=,/=,%=,**=,&=,|=,^=,<<=,和>>=).但是,对于||=这些语句的行为,如果是对象上的方法可能会有所不同,a=并且a是真实的.在这种情况下,a ||= b不会做任何事情(比评估为其他a),而a = a || b将调用a=(a)a的接收器.正如其他人所指出的,当调用a=a具有副作用时,例如向哈希添加键,这可能会有所不同.

  • a ||= ba = b unless a ??

    这些陈述的行为只是在他们评价的时候a才有所不同.在这种情况下,a = b unless a将评估为nil(虽然a仍然不会按预期设置),而a ||= b将评估为a.

  • a ||= bdefined?(a) ? (a || a = b) : (a = b) ????

    仍然没有.当method_missing存在返回truthy值的方法时,这些语句可能不同a.在这种情况下,a ||= b将评估到任何method_missing返回,而不是试图设置a,而defined?(a) ? (a || a = b) : (a = b)将设置ab和评价b.

好吧,好吧,那么什么 a ||= b相当于?有没有办法在Ruby中表达这一点?

好吧,假设我没有忽略任何东西,我相信a ||= b在功能上相当于......()

begin
  a = nil if false
  a || a = b
end
Run Code Online (Sandbox Code Playgroud)

坚持,稍等!这不是第一个带有noop的例子吗?嗯,不太好.还记得我之前说的那个a ||= b只是不等于a || a = b什么时候a是一个未定义的局部变量?好吧,a = nil if false确保a永远不会定义,即使该行永远不会被执行.Ruby中的局部变量是词法范围的.


zee*_*zee 6

如果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
Run Code Online (Sandbox Code Playgroud)