Ruby中的|| =(或 – 等于)是什么意思?
在Ruby中,下面的代码是什么意思?
||= 它有什么意义或语法的理由?
这个问题在Ruby邮件列表和Ruby博客上经常被讨论,现在在Ruby邮件列表上甚至有线程,其唯一目的是收集链接到Ruby邮件列表上的所有其他线程 ,讨论这个问题。
下面是一个: || =(或等于)线程和页面的权威列表
如果您真的想知道发生了什么,请参阅Ruby语言草稿规范的第11.3.1.2节“缩写赋值”。
作为第一个近似,
 a ||= b 
相当于
 a || a = b 
并不等同于
 a = a || b 
 但是,这只是第一个近似值,特别是如果a是未定义的。 语义也是不同的,取决于它是简单的variables赋值,方法赋值还是索引赋值: 
 a ||= b ac ||= b a[c] ||= b 
都被区别对待。
  a ||= b是一个“条件赋值运算符”。 对于a || a = b这是一种不太完整的 (*)速记  a || a = b 。 
 这意味着“ 如果a是未定义的或者是错误的 ( false或nil ),则评估b并将b设置为结果 ”。 
例如:
 > a ||= 1; => 1 > a ||= 2; => 1 > foo = false; => false > foo ||= true; => true > foo ||= false; => true 
  Ruby的短路评估意味着,如果a被定义并评估为真,那么操作员的右手边将不被评估,也不会进行任务分配。 如果a和b都是局部variables,则这种区别是不重要的,但是如果是类的getter / setter方法则是重要的。 
 令人困惑的是,它与其他赋值运算符(如+= )类似,但行为不同。 
  a += b → a = a + b 
  a ||= b → a || a = b a || a = b 
有明显的细微差别,例外,特殊情况 – 但这是它的本质。
*sorting,但不完全
正如ajedi32指出的那样:
a ||= bb⇔aa || a = b?a || a = b?当
a是未定义的局部variables时,这些语句的行为有所不同。 在这种情况下,a ||= b将a ||= b设置为b(并评估为b),而a || a = ba || a = b会NameError: undefined local variable or method 'a' for main:Object引发NameError: undefined local variable or method 'a' for main:Object。
进一步阅读:
简洁而完整的答案
 a ||= b 
以与以下每一行相同的方式进行评估
 a || a = b a ? a : a = b if a then a else a = b end 
–
另一方面,
 a = a || b 
以与以下每一行相同的方式进行评估
 a = a ? a : b if a then a = a else a = b end 
–
编辑:由于AJedi32在评论中指出,这只适用于如果:1. a是一个定义的variables。 2.评估一次和两次不会导致程序或系统状态的差异。
 简而言之, a||=b表示:如果a是undefined, nil or false ,将b赋给b 。 否则,保持不变。 
基本上,
  x ||= y表示 
 如果x有任何值,则不要改变值,否则将x设置为y 。 
 x ||= y 
是
 x || x = y 
“如果x是假的或未定义的,那么x指向y”
这意味着或等于。 它会检查左侧的值是否已定义,然后使用该值。 如果不是,请使用右侧的值。 您可以在Rails中使用它来caching模型中的实例variables。
一个基于Rails的快速示例,我们创build一个函数来获取当前login的用户:
 class User > ActiveRecord::Base def current_user @current_user ||= User.find_by_id(session[:user_id]) end end 
它检查是否设置了@current_user实例variables。 如果是,它将返回它,从而保存数据库调用。 如果没有设置,我们进行调用,然后设置@current_uservariables。 这是一个非常简单的caching技术,但是当您多次在整个应用程序中获取相同的实例variables时非常有用。
 确切地说, a ||= b意思是“如果a是未定义的或者虚假的( false或nil ),将a设置为b并且评估为(即返回) b ,否则评估为”。 
 其他人经常试图通过说a ||= b相当于a ||= b来说明这一点  a || a = b或a = a || b  a = a || b 。 这些等价性可以帮助理解这个概念,但要知道它们在所有情况下都是不准确的。 请允许我解释一下: 
- 
a ||= bb⇔aa || a = ba || a = b?当 a是未定义的局部variables时,这些语句的行为有所不同。 在这种情况下,a ||= b将a ||= b设置为b(并评估为b),而a || a = ba || a = b会NameError: undefined local variable or method 'a' for main:Object引发NameError: undefined local variable or method 'a' for main:Object。
- 
a ||= bb⇔aa = a || ba = a || b?这些陈述的等同性通常是假定的,因为对于其他简化的赋值操作符(即 +=-=,*=/=,%=,**=,&=,|=,^=<<=和>>=)。 然而,对于||=这些语句的行为可能会有所不同,当a=对象的方法是一个真理。 在这种情况下,a ||= b将不做任何事情(除了评估为a),而a = a || ba = a || b将在接收器上打电话a=(a)。 正如其他人所指出的,当调用a=a时会产生不同的副作用,例如将键添加到散列。
- 
a ||= bb⇔aa = b unless a??这些陈述的行为只有在他们评价为真的时才会有所不同。 在这种情况下, a = b unless a将评估nil(但a仍然不会如预期的那样设置),而a ||= b则评估为a。
- 
a ||= bb⇔defined?(a) ? (a || a = b) : (a = b)defined?(a) ? (a || a = b) : (a = b)仍然没有。 当存在返回a的真值的 method_missing方法时,这些语句可能会有所不同。 在这种情况下,a ||= b将评估什么method_missing返回,而不是试图设置a,而defined?(a) ? (a || a = b) : (a = b)defined?(a) ? (a || a = b) : (a = b)将a设为b并评估为b。
 好的,好的,那么a ||= b等于什么? 有没有办法在Ruby中expression这个? 
 那么,假设我没有忽略任何东西,我相信a ||= b在function上等同于…( drumroll ) 
 begin a = nil if false a || a = b end 
 等一下! 这不就是之前noop的第一个例子吗? 那么,不完全。 请记住,我之前说过, a ||= b只是不等于a || a = b  a || a = b当a是一个未定义的局部variables? 那么, a = nil if false ,则a = nil if false确保a永远不会未定义,即使该行从未被执行。  Ruby中的局部variables是词汇范围的。 
 unless x x = y end 
除非x有一个值(不是nil或false),否则将其设置为y
相当于
 x ||= y 
 假设a = 2和b = 3 
 那么, a ||= b将导致a值,即2 。 
 因为当一个评估价值不会导致false或nil 。这就是为什么它不会评估b的价值。 
 现在假设a = nil和b = 3 。 
 那么a ||= b将导致3即b的值。 
 因为它首先尝试评估一个结果nil的价值,所以它评估b的价值。 
在ror应用程序中使用的最好的例子是:
 #To get currently logged in iser def current_user @current_user ||= User.find_by_id(session[:user_id]) end # Make current_user available in templates as a helper helper_method :current_user 
 其中,当且仅当@current_user之前未初始化时, User.find_by_id(session[:user_id])被触发。 
 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[10] = a[10] || 10 
一个变成:
 {10 => true} 
 因为你已经在关键字10处分配了自己的值,默认值为true,所以现在散列是为关键字10定义的,而不是从不首先执行分配。 
这就像懒惰的实例。 如果variables已经被定义了,它将会取这个值,而不是再次创build值。
这是默认的赋值符号
 例如:x || = 1 
 这将检查x是否为零。 如果x确实为零,则它会将其赋值为新值(在本例中为1) 
 更明确: 
 如果x ==零 
  x = 1 
 结束 
 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 
 因为是nil 
 b = 5 a ||= b 
这转化为:
 a = a || b 
这将是
 a = nil || 5 
最后
 a = 5 
现在,如果你再次调用这个:
 a ||= b a = a || b a = 5 || 5 a = 5 b = 6 
现在,如果你再次调用这个:
 a ||= b a = a || b a = 5 || 6 a = 5 
 如果你观察, b值将不会被分配给a 。  a还会有5 。 
它是一个在Ruby中使用的Memoization模式来加速访问器。
 def users @users ||= User.all end 
这基本上转化为:
 @users = @users || User.all 
所以你第一次调用这个方法时会打电话给数据库。
 将来调用这个方法只会返回@users实例variables的值。 
 请记住||=不是一个primefaces操作,所以它不是线程安全的。 根据经验,不要将它用于类方法。 
作为一个常见的误解,一个|| = b不等于a = a || b,但它是行为像一个|| a = b
但是这里有一个棘手的案例
如果a没有定义,则|| a = 42引发NameError,而一个|| = 42则返回42.因此,它们似乎不是等价的expression式。
  ||=被称为条件赋值运算符。 
 它的基本原理是=但是如果一个variables已经被赋值,它将不会执行任何操作。 
第一个例子:
 x ||= 10 
第二个例子:
 x = 20 x ||= 10 
 在第一个例子中, x现在等于10.但是,在第二个例子中, x已经定义为20.所以条件运算符没有效果。 运行x ||= 10后x仍然是20。