Answers:
这个问题在Ruby邮件列表和Ruby博客上讨论得如此频繁,以至于Ruby邮件列表上甚至还有一些线程,其唯一目的是收集指向讨论该问题的Ruby邮件列表上所有其他线程的链接。。
这是一个:|| =(或等于)线程和页面的确定列表
如果您真的想知道发生了什么,请查看Ruby语言草案规范的 11.4.2.3节“缩写的赋值” 。
作为第一近似,
a ||= b
相当于
a || a = b
并且不等同于
a = a || b
但是,这只是一个近似值,尤其a是在未定义的情况下。语义也有所不同,取决于它是简单变量分配,方法分配还是索引分配:
a ||= b
a.c ||= b
a[c] ||= b
都被不同地对待。
a = false; a ||= true并没有做你的答案说,它的作用是“细微差别”。
a ||= b是条件赋值运算符。这意味着如果a未定义或为假,则求值b并设置a为结果。等效地,如果a被定义并评估为真,b则不评估,并且不会发生分配。例如:
a ||= nil # => nil
a ||= 0 # => 0
a ||= 2 # => 0
foo = false # => false
foo ||= true # => true
foo ||= false # => true
令人困惑的是,它看起来与其他赋值运算符(例如 +=),但是行为却有所不同。
a += b 转换为 a = a + ba ||= b 大致翻译成 a || a = b这是的简写a || a = b。区别在于,当a未定义时,a || a = b将引发NameError,而a ||= b将设置a为b。这种区分不重要,如果a和b都是局部变量,,但如果两者都是类的getter / setter方法,。
进一步阅读:
h = Hash.new(0); h[1] ||= 2。现在考虑两个可能的扩展h[1] = h[1] || 2VS h[1] || h[1] = 2。这两个表达式求和,0但第一个表达式不必要地增加了散列的大小。也许这就是Matz选择使||=行为更像第二次扩展的原因。(我基于一个链接到另一个答案的线程之一的示例。)
a || a = b引发NameErrorif如果a未定义。a ||= b不会,而是初始化a并将其设置为b。据我所知,这是两者之间的唯一区别。同样,a = a || b和a ||= b我知道的唯一区别是,如果a=是方法,则无论a返回什么,都将调用它。此外,唯一的区别a = b unless a和a ||= b我所知道的那就是该语句的计算结果为nil,而不是a如果a是truthy。很多近似值,但没有什么等同的...
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是定义的变量。2.评估一次和两次不会导致程序或系统状态的差异。
a为false /零/ undefined,则对其进行两次评估。(但是我不了解Ruby,所以不知道是否可以精确地“评估”左值...)
a || a = b,a ? a : a = b,if a then a else a = b end,和if a then a = a else a = b end将抛出一个错误,如果a是不确定的,而a ||= b并a = a || b不会。此外,a || a = b,a ? a : a = b,if a then a else a = b end,a = a ? a : b,和if a then a = a else a = b end评估a时两次a是truthy,而a ||= b并a = a || b没有。
a || a = b则不会进行a两次评估a。
the end state will be equivalent after the whole line has been evaluated虽然不一定如此。如果a是方法怎么办?方法可能有副作用。例如用public; def a=n; @a=n; end; def a; @a+=1; end; self.a = 5,self.a ||= b将返回6,但self.a ? self.a : self.a = b将返回7.
等于或等于。它检查是否已定义左侧的值,然后使用该值。如果不是,请使用右侧的值。您可以在Rails中使用它在模型中缓存实例变量。
一个基于Rails的快速示例,我们在其中创建一个函数来提取当前登录的用户:
class User > ActiveRecord::Base
def current_user
@current_user ||= User.find_by_id(session[:user_id])
end
end
它检查是否设置了@current_user实例变量。如果是,它将返回它,从而保存数据库调用。如果未设置,则进行调用,然后将@current_user变量设置为该值。这是一种非常简单的缓存技术,但是当您多次从应用程序中获取相同的实例变量时非常有用。
undefined,而且还会触发false和nil,这可能与无关current_user,尤其false是在其他情况下可能会意外发生
x ||= y
是
x || x = y
“如果x为false或未定义,则x指向y”
确切地说,a ||= b表示“如果a未定义或错误(false或nil),则设置a为b并求值为(即返回)b,否则为a”。
其他人常常试图通过说a ||= b等于a || a = b或来说明这一点a = a || b。这些等效项可能有助于理解概念,但请注意,它们并非在所有情况下都是准确的。请允许我解释一下:
a ||= b⇔a || a = b?
当a是未定义的局部变量时,这些语句的行为会有所不同。在这种情况下,a ||= b将设置a为b(并评估为b),而a || a = b将提高NameError: undefined local variable or method 'a' for main:Object。
a ||= b⇔a = a || b?
这些语句的等效常常假设,因为类似的等价是其他真正的简写赋值运算符(即+=,-=,*=,/=,%=,**=,&=,|=,^=,<<=,和>>=)。但是,由于||=这些语句的行为在对象上的方法为真时可能会有所不同。在这种情况下,不会做任何事情(比评估为其他),而将调用上的接收器。正如其他人指出的那样,当调用具有副作用(例如将键添加到哈希)时,这可能会有所作为。a=aa ||= baa = a || ba=(a)aa=a
a ||= b⇔a = b unless a ??
这些陈述的行为仅在它们为真时的评估上有所不同a。在这种情况下,a = b unless a将评估为nil(尽管a仍未按预期设置),而a ||= b将评估为a。
a ||= b ⇔ defined?(a) ? (a || a = b) : (a = b) ????
仍然没有。当method_missing存在返回真值的方法时,这些语句可能会有所不同a。在这种情况下,a ||= b将评估为任何method_missing收益,而不会尝试设置a,而defined?(a) ? (a || a = b) : (a = b)将设置a为b并评估为b。
好吧好吧 是 a ||= b相当于?有没有办法用Ruby表达这一点?
好吧,假设我没有忽略任何东西,我相信a ||= b它在功能上等同于...(drumroll)
begin
a = nil if false
a || a = b
end
坚持,稍等!难道这不是第一个没有noop的例子吗?好吧,不完全是。还记得我之前所说的a ||= b不等同于a || a = b何时a是未定义的局部变量吗?好吧,即使从不执行该行,也要a = nil if false确保它a永远不会被定义。Ruby中的局部变量在词法范围内。
(a=b unless a) or a
a是方法,它将被调用两次而不是一次(如果它是第一次返回真实值)。例如,如果a返回时间较长或有副作用,则可能导致行为不同。
btoa,还是rhs仍然没有分配给lhs,或者换句话说,lhs仍然没有将值设置为rhs吗?
a ||= b我在互联网上找到的最佳答案。谢谢。
假设 a = 2和b = 3
然后,a ||= b 将成为a的值,即2。
就像当a评估某个值时未产生false或nil..这就是为什么它ll不评估b的值。
现在假设 a = nil和b = 3。
然后a ||= b将得出 3e b的值。
由于它首先尝试评估结果为nil..的a的值,因此它评估了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
在,User.find_by_id(session[:user_id])且仅当@current_user之前未初始化时才触发。
a || = b
表示“ a”中是否存在任何值,并且您不想使用该值更改保持值,否则,如果“ a”不具有任何值,则使用值“ b”。
简单的单词,如果左侧不为null,则指向现有值,否则指向右侧的值。
还请记住,这||=不是原子操作,因此它不是线程安全的。根据经验,请勿将其用于类方法。
此ruby-lang语法。正确的答案是检查ruby-lang文档。所有其他解释都难以理解。
“ ruby-lang docs缩写作业”。
https://docs.ruby-lang.org/zh/2.4.0/syntax/assignment_rdoc.html#label-Abbreviated+Assignment
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中用于加速访问器的记忆模式。
def users
@users ||= User.all
end
这基本上转化为:
@users = @users || User.all
因此,您将在首次调用此方法时对数据库进行调用。
将来对该方法的调用将仅返回@users实例变量的值。
a ||= b与说a = b if a.nil?或a = b unless a
但是,这三个选项是否都显示相同的性能?使用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 unless a对于新手来说更容易阅读,这是不言而喻的。
注1:多次重复分配行的原因是为了减少所测量时间的环路开销。
注意2:如果我a=nil在每次作业前都没有设置nil,结果将是相似的。