以下代码在Ruby中的含义是什么?
||=
Run Code Online (Sandbox Code Playgroud)
它的语法是否有任何意义或原因?
Ste*_*ett 558
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
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设置a为b.
进一步阅读:
Jör*_*tag 175
这个问题经常在Ruby邮件列表和Ruby博客上讨论过,现在甚至Ruby邮件列表上都有线程,其唯一的目的是收集Ruby邮件列表上讨论这个问题的所有其他线程的链接..
如果您真的想知道发生了什么,请查看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)
都被区别对待.
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.评估一次和两次不会导致程序或系统状态的差异.
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变量设置为该调用.这是一种非常简单的缓存技术,但是当您在应用程序中多次获取相同的实例变量时非常适合.
x ||= y
Run Code Online (Sandbox Code Playgroud)
是
x || x = y
Run Code Online (Sandbox Code Playgroud)
"如果x为false或未定义,则x指向y"
准确地说,a ||= b是指"如果a未定义或falsy(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=并且a是真实的.在这种情况下,a ||= b不会做任何事情(比评估为其他a),而a = a || b将调用a=(a)上a的接收器.正如其他人所指出的,当调用a=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存在返回truthy值的方法时,这些语句可能不同a.在这种情况下,a ||= b将评估到任何method_missing返回,而不是试图设置a,而defined?(a) ? (a || a = b) : (a = b)将设置a于b和评价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中的局部变量是词法范围的.
如果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)
| 归档时间: |
|
| 查看次数: |
92537 次 |
| 最近记录: |