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

2018-12-31 03:04发布

What does the following code mean in Ruby?

||=

Does it have any meaning or reason for the syntax?

20条回答
明月照影归
2楼-- · 2018-12-31 03:22
Basically,


x ||= y means

if x has any value leave it alone and do not change the value, otherwise set x to y.

查看更多
冷夜・残月
3楼-- · 2018-12-31 03:23

Suppose a = 2 and b = 3

THEN, a ||= b will be resulted to a's value i.e. 2.

As when a evaluates to some value not resulted to false or nil.. That's why it ll not evaluate b's value.

Now Suppose a = nil and b = 3.

Then a ||= b will be resulted to 3 i.e. b's value.

As it first try to evaluates a's value which resulted to nil.. so it evaluated b's value.

The best example used in ror app is :

#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

Where, User.find_by_id(session[:user_id]) is fired if and only if @current_user is not initialized before.

查看更多
千与千寻千般痛.
4楼-- · 2018-12-31 03:24

It's like lazy instantiation. If the variable is already defined it will take that value instead of creating the value again.

查看更多
墨雨无痕
5楼-- · 2018-12-31 03:27

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.

查看更多
春风洒进眼中
6楼-- · 2018-12-31 03:31

||= is a conditional assignment operator

  x ||= y

is equivalent to

  x = x || y

or alternatively

if defined?(x) and x
    x = x
else 
    x = y
end
查看更多
琉璃瓶的回忆
7楼-- · 2018-12-31 03:33
b = 5
a ||= b

This translates to:

a = a || b

which will be

a = nil || 5

so finally

a = 5

Now if you call this again:

a ||= b
a = a || b
a = 5 || 5
a = 5

b = 6

Now if you call this again:

a ||= b
a = a || b
a = 5 || 6
a = 5 

If you observe, b value will not be assigned to a. a will still have 5.

Its a Memoization Pattern that is being used in Ruby to speed up accessors.

def users
  @users ||= User.all
end

This basically translates to:

@users = @users || User.all

So you will make a call to database for the first time you call this method.

Future calls to this method will just return the value of @users instance variable.

查看更多
登录 后发表回答