What does ||= (or-equals) mean in Ruby?

前端 未结 23 2868
情书的邮戳
情书的邮戳 2020-11-21 23:20

What does the following code mean in Ruby?

||=

Does it have any meaning or reason for the syntax?

23条回答
  •  伪装坚强ぢ
    2020-11-21 23:46

    To be precise, a ||= b means "if a is undefined or falsy (false or nil), set a to b and evaluate to (i.e. return) b, otherwise evaluate to a".

    Others often try to illustrate this by saying that a ||= b is equivalent to a || a = b or a = a || b. These equivalencies can be helpful for understanding the concept, but be aware that they are not accurate under all conditions. Allow me to explain:

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

      The behavior of these statements differs when a is an undefined local variable. In that case, a ||= b will set a to b (and evaluate to b), whereas a || a = b will raise NameError: undefined local variable or method 'a' for main:Object.

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

      The equivalency of these statements are often assumed, since a similar equivalence is true for other abbreviated assignment operators (i.e. +=,-=,*=,/=,%=,**=,&=,|=,^=,<<=, and >>=). However, for ||= the behavior of these statements may differ when a= is a method on an object and a is truthy. In that case, a ||= b will do nothing (other than evaluate to a), whereas a = a || b will call a=(a) on a's receiver. As others have pointed out, this can make a difference when calling a=a has side effects, such as adding keys to a hash.

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

      The behavior of these statements differs only in what they evaluate to when a is truthy. In that case, a = b unless a will evaluate to nil (though a will still not be set, as expected), whereas a ||= b will evaluate to a.

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

      Still no. These statements can differ when a method_missing method exists which returns a truthy value for a. In this case, a ||= b will evaluate to whatever method_missing returns, and not attempt to set a, whereas defined?(a) ? (a || a = b) : (a = b) will set a to b and evaluate to b.

    Okay, okay, so what is a ||= b equivalent to? Is there a way to express this in Ruby?

    Well, assuming that I'm not overlooking anything, I believe a ||= b is functionally equivalent to... (drumroll)

    begin
      a = nil if false
      a || a = b
    end
    

    Hold on! Isn't that just the first example with a noop before it? Well, not quite. Remember how I said before that a ||= b is only not equivalent to a || a = b when a is an undefined local variable? Well, a = nil if false ensures that a is never undefined, even though that line is never executed. Local variables in Ruby are lexically scoped.

提交回复
热议问题