web-dev-qa-db-ja.com

Rubyでは|| =(or-equals)とはどういう意味ですか?

次のコードはRubyで何を意味しますか?

||=

構文に意味や理由はありますか?

318
collimarco

この質問はRubyメーリングリストやRubyブログで頻繁に議論されているため、現在、Rubyメーリングリストにもスレッドがあります。この問題について議論するRubyメーリングリスト上の他のすべてのスレッドへのリンクを収集します。

以下にその1つを示します。 =(または等しい)スレッドとページの決定的なリスト

本当に何が起こっているのか知りたい場合は、 Ruby Language Draft Specification のセクション11.4.2.3「略語の割り当て」をご覧ください。

最初の近似として、

a ||= b

に等しい

a || a = b

およびnotと同等

a = a || b

ただし、特にaが未定義の場合、これは最初の近似にすぎません。また、セマンティクスは、単純な変数の割り当て、メソッドの割り当て、またはインデックスの割り当てによって異なります。

a    ||= b
a.c  ||= b
a[c] ||= b

すべて異なる方法で処理されます。

173
Jörg W Mittag

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 += ba = a + bに変換されます
  • a ||= bは、おおよそa || a = bに変換されます

a || a = bの略記法です。違いは、aが未定義の場合、a || a = bNameErrorを発生させますが、a ||= babに設定します。 abが両方ともローカル変数である場合、この区別は重要ではありませんが、どちらかがクラスのゲッター/セッターメソッドである場合は重要です。

参考文献:

545
Steve Bennett

簡潔で完全な回答

a ||= b

以下の行のeachと同じ方法で評価します

a || a = b
a ? a : a = b
if a then a else a = b end

-

一方、

a = a || b

以下の行のeachと同じ方法で評価します

a = a ? a : b
if a then a = a else a = b end

-

編集:AJedi32がコメントで指摘したように、これは以下の場合にのみ当てはまります。1. aが定義済み変数である。 2. 1回と2回評価しても、プログラムまたはシステムの状態に違いはありません。

32
the_minted

つまり、a||=bは次を意味します。aundefined, nil or falseである場合、baに割り当てます。それ以外の場合は、aをそのまま保持します。

24
vidang


x ||= y

xに値がある場合、そのままにして値を変更しないでください。そうでない場合は、xyに設定します

16
nPcomp

それは次と等しいことを意味します。左側の値が定義されているかどうかを確認してから、それを使用します。そうでない場合は、右側の値を使用します。 Railsで使用して、モデルのインスタンス変数をキャッシュできます。

Railsベースの簡単な例。現在ログインしているユーザーを取得する関数を作成します。

class User > ActiveRecord::Base

  def current_user
    @current_user ||= User.find_by_id(session[:user_id])
  end

end

@current_userインスタンス変数が設定されているかどうかを確認します。もしそうなら、それはそれを返し、それによってデータベース呼び出しを保存します。ただし、設定されていない場合は、呼び出しを行ってから@current_user変数を設定します。これは非常に単純なキャッシュ手法ですが、アプリケーション全体で同じインスタンス変数を複数回フェッチする場合に最適です。

11
Jamie Rumbelow
x ||= y

x || x = y

「xがfalseまたは未定義の場合、xはyを指す」

a = 2b = 3があるとします

その後、a ||= baの値、つまり2になります。

falseまたはnilにならない値に評価されるとき。それがllbの値を評価しない理由です。

a = nilおよびb = 3と仮定します。

a ||= b3、つまり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が以前に初期化されていない場合にのみ起動されます。

3
Pankhuri

unless x x = y end

xに値(nilまたはfalseではない)がなければ、yに等しく設定します

に等しい

x ||= y

3
0r4cl3

a || = b

「a」に値が存在し、その値を使用して値を変更したくない場合、「a」に値がない場合は「b」の値を使用します。

単純な単語は、左側がヌルでない場合は既存の値を指し、そうでない場合は右側の値を指します。

2
SHUBHAM SHARMA

それは怠instantなインスタンス化のようなものです。変数が既に定義されている場合、値を再度作成する代わりに、その値が使用されます。

2
mukh007

||=はアトミック操作ではないため、スレッドセーフではないことも覚えておいてください。経験則として、クラスメソッドには使用しないでください。

2
Luca Guidi

これはデフォルトの割り当て表記です

例:x || = 1
これは、xがnilかどうかを確認します。 xが実際にnilの場合、新しい値(この例では1)を割り当てます。

より明示的に:
if x == nil
x = 1
終わり

2
Max Rogers

=条件付き代入演算子

  x ||= y

に等しい

  x = x || y

または代替

if defined?(x) and x
    x = x
else 
    x = y
end
2
Sunda
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

になります:

{10 => true}

キー10に自身の値を割り当てたため、デフォルトではtrueに設定されているため、最初に割り当てを実行するのではなく、キー10に対してハッシュが定義されます。

2
RileyE

よくある誤解として、a ||= ba = a || bと同等ではありませんが、a || a = bのように動作します。

しかし、ここでは扱いにくいケースがあります。 aが定義されていない場合、a || a = 42NameErrorを上げ、a ||= 4242を返します。したがって、それらは同等の式ではないようです。

1
tessie
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に割り当てられません。 a5のままです。

アクセサーを高速化するためにRubyで使用されているメモ型パターン。

def users
  @users ||= User.all
end

これは基本的に次のように変換されます:

@users = @users || User.all

したがって、このメソッドを初めて呼び出すときは、データベースを呼び出します。

今後このメソッドを呼び出すと、@usersインスタンス変数の値が返されます。

0

||=は、条件付き代入演算子と呼ばれます。

基本的には=として機能しますが、変数既に割り当てられているが何もしない場合を除きます。

最初の例:

x ||= 10

2番目の例:

x = 20
x ||= 10

最初の例では、xは10になりました。ただし、2番目の例では、xはすでに20として定義されています。したがって、条件演算子は効果がありません。 xは、x ||= 10の実行後も20です。

0
Charlie Wood
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

anilだったため

0
fuzz

a ||= bは、a = b if a.nil?またはa = b unless aと同じです。

しかし、3つのオプションはすべて同じパフォーマンスを示していますか? 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

pCで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を実行した場合の結果は似ています。

0
Ymox

||=は、left == nil(またはundefinedまたはfalse)の場合にのみ値を右に割り当てます。

0
H. Almidan