以下代码在Ruby中意味着什么?
||=
语法是否有任何意义或原因?
答案 0 :(得分:530)
a ||= b
是条件赋值运算符。这意味着如果a
未定义或falsey,则评估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 + b
a ||= b
大致翻译为a || a = b
这是a || a = b
的近似简写。不同之处在于,当a
未定义时,a || a = b
会引发NameError
,而a ||= b
会将a
设置为b
。如果a
和b
都是局部变量,那么这种区别就不重要了,但如果它们是类的getter / setter方法则很重要。
进一步阅读:
答案 1 :(得分:170)
在Ruby邮件列表和Ruby博客上经常讨论这个问题,现在Ruby邮件列表上甚至有线程,其唯一目的是收集所有其他线程的链接在讨论这个问题的Ruby邮件列表上。
这是一个:The definitive list of ||= (OR Equal) threads and pages
如果确实想知道发生了什么,请查看Ruby Language Draft Specification的第11.4.2.3节“缩写分配”。
作为第一个近似值,
a ||= b
相当于
a || a = b
和不等同于
a = a || b
然而,这只是第一次近似,特别是如果未定义a
。语义也有所不同,这取决于它是简单的变量赋值,方法赋值还是索引赋值:
a ||= b
a.c ||= b
a[c] ||= b
都被区别对待。
答案 2 :(得分:32)
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.评估一次和两次不会导致程序或系统状态的差异。
答案 3 :(得分:23)
简而言之,a||=b
表示:如果a
为undefined, nil or false
,请将b
分配给a
。否则,请保持a
完整。
答案 4 :(得分:12)
x ||= y
表示
如果x
有任何值,请单独留下并且不要更改值,否则
将x
设置为y
答案 5 :(得分:10)
这意味着或等于。它检查左侧的值是否已定义,然后使用它。如果不是,请使用右侧的值。您可以在Rails中使用它来缓存模型中的实例变量。
基于Rails的快速示例,我们创建一个函数来获取当前登录的用户:
class User > ActiveRecord::Base
def current_user
@current_user ||= User.find_by_id(session[:user_id])
end
end
检查是否设置了@current_user实例变量。如果是,它将返回它,从而保存数据库调用。如果没有设置,我们进行调用,然后将@current_user变量设置为该调用。这是一种非常简单的缓存技术,但是当您在应用程序中多次获取相同的实例变量时,它非常适用。
答案 6 :(得分:8)
x ||= y
是
x || x = y
“如果x为假或未定义,则x指向y”
答案 7 :(得分:7)
准确地说,a ||= b
表示"如果a
未定义或假(false
或nil
),请将a
设置为{{ 1}}并评估为(即返回)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
?
通常假设这些陈述的等效性,因为其他abbreviated assignment运算符(即a = a || b
,+=
,-=
,{{1} },*=
,/=
,%=
,**=
,&=
,|=
和^=
)。但是,对于<<=
,当>>=
是对象上的方法且||=
是真实的时,这些语句可能的行为会有所不同。在这种情况下,a=
将不执行任何操作(评估为a
除外),而a ||= b
将在a
的接收方上调用a = a || b
。正如others指出的那样,当调用a=(a)
有副作用时,例如向哈希添加键时,这会有所不同。
a
⇔a=a
??
这些陈述的行为仅在a ||= b
真实时评估的内容上有所不同。在这种情况下,a = b unless a
将评估为a
(尽管a = b unless a
仍未按预期设置),而nil
将评估为a
。< / p>
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
等同于什么?有没有办法在Ruby中表达这个?
好吧,假设我没有忽视任何事情,我相信b
在功能上等同于...( drumroll )
a ||= b
等一下!难道这不是第一个带有noop的例子吗?嗯,不太好。还记得我之前说过a ||= b
在begin
a = nil if false
a || a = b
end
是未定义的局部变量时只与a ||= b
不等同吗?好吧,a || a = b
确保永远不会定义a
,即使该行永远不会被执行。 Ruby中的局部变量是词法范围的。
答案 8 :(得分:3)
如果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
答案 9 :(得分:3)
unless x
x = y
end
除非x具有值(它不是nil或false),否则将其设置为y
相当于
x ||= y
答案 10 :(得分:3)
假设a = 2
和b = 3
然后,a ||= b
会产生a
的值,即2
。
当评估某个值未导致false
或nil
时...这就是为什么ll
不评估b
的值。
现在假设a = nil
和b = 3
。
然后a ||= b
会产生3
,即b
的值。
首先尝试评估导致nil
的值...所以评估b
的值。
ror app中使用的最佳示例是:
#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
。
答案 11 :(得分:2)
这是默认的赋值表示法
例如:x || = 1
这将检查x是否为零。如果x确实为零,则它将为其分配新值(在我们的示例中为1)
更明确:
如果x == nil
x = 1
端
答案 12 :(得分:2)
还请记住docker run -it --entrypoint bash dockerfile/rabbitmq:latest
[ root@0c5920d3559e:/data ]$ rabbitmq-start
不是原子操作,因此它不是线程安全的。根据经验,不要将它用于类方法。
答案 13 :(得分:2)
这就像懒惰的实例化。 如果已经定义了变量,它将采用该值而不是再次创建该值。
答案 14 :(得分:2)
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
a成为:
{10 => true}
因为你已经在键10
分配了自己的值,默认为true,所以现在为键10
定义了哈希,而不是从不首先执行赋值
答案 15 :(得分:1)
作为一种常见的误解,a ||= b
不等同于a = a || b
,但其行为与a || a = b
相同。
但这是一个棘手的案例。如果未定义a
,则a || a = 42
会引发NameError
,而a ||= 42
会返回42
。所以,它们似乎不是等同的表达方式。
答案 16 :(得分:1)
此ruby-lang语法。正确的答案是检查ruby-lang文档。 所有其他说明都难以理解。
“ ruby-lang docs缩写分配”。
https://docs.ruby-lang.org/en/2.4.0/syntax/assignment_rdoc.html#label-Abbreviated+Assignment
答案 17 :(得分:0)
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
答案 18 :(得分:0)
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
。
它是一个Memoization模式,在Ruby中用于加速访问器。
def users
@users ||= User.all
end
这基本上转化为:
@users = @users || User.all
因此,您第一次调用此方法时将调用数据库。
将来对此方法的调用只会返回@users
实例变量的值。
答案 19 :(得分:0)
|| = 是条件赋值运算符
x ||= y
等同于
x = x || y
或
if defined?(x) and x
x = x
else
x = y
end
答案 20 :(得分:0)
a || = b
表示'a'中是否存在任何值,并且您不想使用该值更改保持值,否则,如果'a'没有任何值,则使用'b'值。
简单的单词,如果左侧不为null,则指向现有值,否则指向右侧的值。
答案 21 :(得分:0)
||=
仅在left == nil(或未定义或false)时才向右分配值。
答案 22 :(得分:-1)
INSERT INTO `Patients`
(`patientId`, `name`, `address`, `etage`, `Door`, `Elevator`, `key_number`,
`medicineId`, `doctorId`)
VALUES (109, 'Muller', 'bla bla bla ', 3, 'links', 1 , 'S12' ,'m9' , 'D11');
INSERT INTO `PatientsDetail` (`patientId`, `lid`)
VALUES
(109, 02.0),
(109, 2.10),
(109, 2.30);
被称为条件赋值运算符。
它基本上可以作为||=
使用,但有一个例外,即如果已经指定了变量 则它将不执行任何操作。
第一个例子:
=
第二个例子:
x ||= 10
在第一个示例中,x = 20
x ||= 10
现在等于10.但是,在第二个示例中,x
已经定义为20.因此条件运算符无效。运行x
后,x
仍然是20。
答案 23 :(得分:-1)
'gitlab-runner' is not recognized as an internal or external command,
operable program or batch file.
与说a ||= b
或a = b if a.nil?
但是,所有3个选项都显示相同的性能吗?使用Ruby 2.5.1,
a = b unless a
在我的PC上花费0.099秒,而
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.062秒。快了将近40%。
然后我们还有:
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.166秒。
并不是说这通常会对性能产生重大影响,但是如果您确实需要最后的优化,请考虑此结果。
顺便说一句: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
对于新手来说更容易阅读,它是不言自明的。
注1:多次重复分配行的原因是为了减少所测量时间的循环开销。
注2:如果我在每次作业前都没做a = 1 unless a
无,结果将是相似的。