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


340

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

||=

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

回答:


175

この質問は、RubyメーリングリストとRubyブログで頻繁に議論されているため、Rubyメーリングリストには、他のすべてのスレッドへのリンクを収集することのみを目的としたスレッドさえあります。この問題を議論するRubyメーリングリストの。

ここに1つあります:|| =(または等しい)スレッドとページの決定的なリスト

何が起こっているのかを本当に知りたい場合は、Ruby言語ドラフト仕様のセクション11.4.2.3「省略された割り当て」を参照してください。

最初の近似として、

a ||= b

に相当

a || a = b

と同等ではありません

a = a || b

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

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

すべてが異なって扱われます。


2
2番目のリンクはビットの腐敗に悩まされています(stackoverflow.com/users/540162/nightfirecatによるメタからのコメント)。
Andrew Grimm、

330
それは非常に不可解な答えです。短い答えは次のようです:a || = bは、aが未定義の場合はbの値を割り当て、それ以外の場合はそのままにします。(わかりました、ニュアンスと特殊なケースがありますが、それは基本的なケースです。)
スティーブベネット

20
@SteveBennett:私はあなたの答えが「ニュアンス」を言うと言っていることをa = false; a ||= trueないという事実を呼ばないでしょう。
イェルクWミッターク

23
たぶん、この質問が何度も尋ねられたと人々が答え続けるので、この質問は何度も尋ねられたのでしょう。
2015

8
この答えにより、複数のスレッドがある理由が簡単にわかります。初心者の帽子を使ってこの質問への回答を検索しようとすると、すべての回答が明確ではないことがわかります。たとえば、これはあなたがそうでないものを言っているだけです。私はあなたの答えを改善し、初心者のための簡単な答えを与えることをお勧め:= Bない限り
アーノルド・ロア

594

a ||= b条件付き代入演算子です。これはaが未定義またはfalseの場合、評価して結果に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ローカル変数の両方が、どちらかがクラスのゲッター/セッターメソッドである場合は重要です。

参考文献:


52
この答えをありがとう、それははるかに理にかなっています。
Tom Hert 2013年

十分に検索していませんが、a = aとは対照的にこれを使用する理由はまだわかりません|| b。多分私の個人的な意見だけかもしれませんが、そのようなニュアンスが存在することは少しばかげています...
dtc

2
@dtc、検討してくださいh = Hash.new(0); h[1] ||= 2。次に、考えられる2つの拡張h[1] = h[1] || 2vs について考えh[1] || h[1] = 2ます。どちらの式も評価されます0が、最初の式はハッシュのサイズを不必要に大きくします。おそらくそれが、Matzが||=2番目の拡張のように動作させることを選択した理由です。(これは、別の回答でリンクされているスレッドの1
つからの

1
詳細については他の回答も気に入っていますが、この回答はシンプルであるため気に入っています。Rubyを学ぶ人にとって、これは私たちが必要とする回答のタイプです。|| =の意味がわかっていれば、質問の表現が異なる可能性があります。
OBCENEIKON 14

1
Fyi、if が未定義の場合にa || a = b発生します。しませんが、初期化してに設定します。私が知る限り、それが2つの違いだけです。同様に、私が認識しているとの唯一の違いは、メソッドの場合、何が返されるかに関係なく呼び出されるということです。また、私が認識しているとの唯一の違いは、そのステートメントがif が真実である代わりに評価されることです。近似はたくさんありますが、まったく同等のものはありません...NameErroraa ||= baba = a || ba ||= ba=aa = b unless aa ||= bnilaa
Ajedi32

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. 1回と2回評価しても、プログラムやシステムの状態に違いはありません。


1
確かですか?これは、aがfalse /ゼロ/未定義の場合、2回評価されることを意味します。(しかし、私はRubyを知らないので、左辺値を正確に「評価」できるかどうかわかりません...)
Steve Bennett

あなたの言っていることがわかります。2つの行が同等であることの意味は、行全体が評価された後に最終状態が同等になることです。つまり、a、bの値と返される値を意味します。Rubyインタープリターがさまざまな状態(aのいくつかの評価など)を使用してそこに到達するかどうかは、完全に可能です。ルビー通訳のエキスパートはいますか?
the_minted 2013年

3
これは正しくありません。a || a = ba ? a : a = bif a then a else a = b end、およびif a then a = a else a = b end場合は、エラーをスローしますa定義されていないのに対し、a ||= ba = a || bしません。また、a || a = ba ? a : a = bif a then a else a = b enda = a ? a : b、とif a then a = a else a = b end評価するa二回ときatruthyあり、一方a ||= b及びa = a || bません。
Ajedi32 2014

1
*修正:がtrueの場合、2回a || a = b評価されません。aa
Ajedi32 14

1
@the_minted the end state will be equivalent after the whole line has been evaluatedそれは必ずしも真実ではありません。どのような場合aの方法はありますか?メソッドには副作用があります。例:With public; def a=n; @a=n; end; def a; @a+=1; end; self.a = 5self.a ||= b6 self.a ? self.a : self.a = bを返しますが、7を返します
Ajedi32

27

要するに、a||=b手段:Ifはaあるundefined, nil or false割り当てba。それ以外の場合は、そのままにしaてください。


16
基本的に、


x ||= y 手段

x値がある場合はそのままにし、値は変更しないでください。それ以外の場合xy


13

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

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

class User > ActiveRecord::Base

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

end

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


8
これは間違っています。Ruby-Forum.Com/topic/151660とそこに提供されているリンクをお読みください。
イェルクWミッターク

1
@Jo(umlaut)rg、何が悪いのかわかりません。あなたのリンクは他のリンクのリストです。それが間違っている理由は本当の説明ではなく、あなたの価値観のように聞こえます。
eggmatters 2014年

この答えはそれのためだけでなく、上のトリガ、間違っているundefined、だけでなく、上falsenilの関連ではないかもしれません、current_userが、特にfalse他のケースでunexpectecdすることができ
dfherr

この答えが示す可能性のある不完全性にもかかわらず(nil / falseでは機能しない)、|| =を使用する理由を説明するのはこれが最初なので、ありがとうございます!
ジョナサントゥズマン


8

正確に言うa ||= bと、「a未定義または偽の(falseまたはnil)の場合、に設定さabて評価される(つまり、戻る)b、それ以外の場合は」を意味しaます。

他の人a ||= bは、a || a = bやと同等であると言ってこれを説明しようとすることがよくありa = a || bます。これらの同等性は概念を理解するのに役立ちますが、すべての条件下で正確ではないことに注意してください。説明させてください:

  • a ||= ba || a = b

    aが未定義のローカル変数である場合、これらのステートメントの動作は異なります。その場合、a ||= bはに設定さab(そしてに評価されますb)、a || a = bレイズしNameError: undefined local variable or method 'a' for main:Objectます。

  • a ||= ba = a || b

    これらのステートメントの等価は、多くの場合、同様の等価性は、他についても同様であるため、想定される略記代入演算子(すなわち+=-=*=/=%=**=&=|=^=<<=、および>>=)。ただし、||=これらのステートメントの動作は、がオブジェクトのメソッドであり、真実である場合は異なる場合があります。その場合には、(に評価する以外に何もしません一方、)を呼び出します上の受信機。他の人が指摘してきた通話をする場合、これは違いを作ることができ、このようなハッシュにキーを追加するなどの副作用があります。a=aa ||= baa = a || ba=(a)aa=a

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

    これらのステートメントの動作aは、真実であると評価されたときにのみ異なります。その場合、a = b unless aはに評価されますnil(ただしa、期待どおりにまだ設定されません)、a ||= bはに評価されaます。

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

    まだ違います。のmethod_missing真の値を返すメソッドが存在する場合、これらのステートメントは異なる場合がありますa。この場合、a ||= bmethod_missing戻り値に評価されa、を設定しようとしませんが、defined?(a) ? (a || a = b) : (a = b)に設定さab、に評価されbます。

大丈夫、大丈夫、だから何です a ||= bと同等?Rubyでこれを表現する方法はありますか?

まあ、私は何も見落とさないと仮定すると、私a ||= bは機能的には...と同等だと信じています(ドラムロール

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

つかまっている!それはその前に何もしない最初の例ではないですか?まあ、かなり。それは前に私が言ったか覚えているa ||= bだけと等価ではないa || a = b時にa未定義のローカル変数がありますか?まあ、その行が実行されるa = nil if falseことaはありませんが、それが未定義になることはありません。Rubyのローカル変数はレキシカルにスコープされています。


したがって、3番目の拡張例:(a=b unless a) or a
vol7ron、2015年

1
@ vol7ron#2と同様の問題があります。aがメソッドの場合、1回ではなく2回呼び出されます(最初に真の値を返す場合)。たとえば、a戻るのに長い時間がかかる場合や副作用がある場合などは、動作が異なる可能性があります。
Ajedi32、2015年

また、最初の文は、assign btoaと言ってはいけませんか?rhsはまだlhsに割り当てていませんか?つまり、lhsはまだその値をrhsに設定していませんか?
vol7ron、2015

a ||= bインターネットで見つけた最良の答え。ありがとう。
Eric Duminil 2017年

3

unless x x = y end

xに値がない(nilでもfalseでもない)場合を除き、yと等しく設定します

に相当

x ||= y


3

想定 a = 2してb = 3

その後、a ||= b 結果はaの値になります2

の結果がfalsenil..に評価されない場合のように、それがの値をll評価しない理由bです。

今、仮定 a = nilb = 3ます。

次にa ||= b3ie 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

a || = b

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

単純な単語。左側がnullでない場合は既存の値を指し、それ以外の場合は右側の値を指します。


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}

keyに自身の値を割り当てたため(10デフォルトはtrue)、ハッシュを定義するの10は、最初に割り当てを実行するのではなく、key です。


2

遅延インスタンス化のようなものです。変数が既に定義されている場合は、値を再度作成するのではなく、その値を取ります。


2

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


2

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

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

より明示的な:
X == nilの場合
、X = 1つの
エンド


どちらnilfalse、またはそれだけではないnil
Alex Poca

2

|| =条件付き代入演算子です

  x ||= y

に相当

  x = x || y

または代わりに

if defined?(x) and x
    x = x
else 
    x = y
end

2

に値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

1

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

しかし、ここにはトリッキーなケースがあります。aが定義されていない場合、a || a = 42が発生しNameError、while a ||= 42が戻ります42。したがって、それらは同等の表現ではないようです。


1

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


おそらく、右ではなく「左に値を割り当てる」ことを意味していました
Maysam Torabi


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


ここで回答日はいつですか。なぜ年が表示されないのですか?
Shiv 2015

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値はに割り当てられませんaaまだ持っています5ます。

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実行後も20 x ||= 10です。


-2

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 を実行しても結果は同じです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.