回答:
この質問は、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
すべてが異なって扱われます。
a = false; a ||= true
しないという事実を呼ばないでしょう。
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
ローカル変数の両方が、どちらかがクラスのゲッター/セッターメソッドである場合は重要です。
参考文献:
h = Hash.new(0); h[1] ||= 2
。次に、考えられる2つの拡張h[1] = h[1] || 2
vs について考えh[1] || h[1] = 2
ます。どちらの式も評価されます0
が、最初の式はハッシュのサイズを不必要に大きくします。おそらくそれが、Matzが||=
2番目の拡張のように動作させることを選択した理由です。(これは、別の回答でリンクされているスレッドの1
a || a = b
発生します。しませんが、初期化してに設定します。私が知る限り、それが2つの違いだけです。同様に、私が認識しているとの唯一の違いは、メソッドの場合、何が返されるかに関係なく呼び出されるということです。また、私が認識しているとの唯一の違いは、そのステートメントがif が真実である代わりに評価されることです。近似はたくさんありますが、まったく同等のものはありません...NameError
a
a ||= b
a
b
a = a || b
a ||= b
a=
a
a = b unless a
a ||= b
nil
a
a
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回評価しても、プログラムやシステムの状態に違いはありません。
a
がfalse /ゼロ/未定義の場合、2回評価されることを意味します。(しかし、私はRubyを知らないので、左辺値を正確に「評価」できるかどうかわかりません...)
a || a = b
、a ? a : a = b
、if a then a else a = b end
、およびif a then a = a else a = b end
場合は、エラーをスローしますa
定義されていないのに対し、a ||= b
とa = a || b
しません。また、a || a = b
、a ? a : a = b
、if a then a else a = b end
、a = a ? a : b
、とif a then a = a else a = b end
評価するa
二回ときa
truthyあり、一方a ||= b
及びa = a || b
ません。
a || a = b
評価されません。a
a
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 = 5
はself.a ||= b
6 self.a ? self.a : self.a = b
を返しますが、7を返します
等しいか等しいという意味です。左側の値が定義されているかどうかを確認し、それを使用します。そうでない場合は、右側の値を使用します。Railsでこれを使用して、インスタンス変数をモデルにキャッシュできます。
Railsベースの簡単な例。現在ログインしているユーザーを取得する関数を作成します。
class User > ActiveRecord::Base
def current_user
@current_user ||= User.find_by_id(session[:user_id])
end
end
@current_userインスタンス変数が設定されているかどうかを確認します。存在する場合はそれを返し、データベース呼び出しを保存します。ただし、設定されていない場合は、呼び出しを行い、@ current_user変数をそれに設定します。これは非常に単純なキャッシング手法ですが、アプリケーション全体で同じインスタンス変数を複数回フェッチする場合に最適です。
undefined
、だけでなく、上false
とnil
の関連ではないかもしれません、current_user
が、特にfalse
他のケースでunexpectecdすることができ
x ||= y
です
x || x = y
「xがfalseまたは未定義の場合、xはyを指します」
正確に言うa ||= b
と、「a
未定義または偽の(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
真の値を返すメソッドが存在する場合、これらのステートメントは異なる場合があります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
つかまっている!それはその前に何もしない最初の例ではないですか?まあ、かなり。それは前に私が言ったか覚えているa ||= b
だけと等価ではないa || a = b
時にa
未定義のローカル変数がありますか?まあ、その行が実行されるa = nil if false
ことa
はありませんが、それが未定義になることはありません。Rubyのローカル変数はレキシカルにスコープされています。
(a=b unless a) or a
a
がメソッドの場合、1回ではなく2回呼び出されます(最初に真の値を返す場合)。たとえば、a
戻るのに長い時間がかかる場合や副作用がある場合などは、動作が異なる可能性があります。
b
toa
と言ってはいけませんか?rhsはまだlhsに割り当てていませんか?つまり、lhsはまだその値をrhsに設定していませんか?
a ||= b
インターネットで見つけた最良の答え。ありがとう。
想定 a = 2
してb = 3
その後、a ||= b
結果はa
の値になります2
。
の結果がfalse
やnil
..に評価されない場合のように、それがの値をll
評価しない理由b
です。
今、仮定 a = nil
しb = 3
ます。
次にa ||= b
、 3
ie 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
ます。
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 です。
これはデフォルトの割り当て表記です
例:x || = 1
これは、xがnilかどうかを確認します。xが本当にnilの場合、その新しい値(この例では1)を割り当てます
より明示的な:
X == nilの場合
、X = 1つの
エンド
nil
かfalse
、またはそれだけではないnil
||=
left == nil(または未定義またはfalse)の場合にのみ、値をrightに割り当てます。
このruby-lang構文。正解は、ruby-langのドキュメントを確認することです。他のすべての説明は難読化します。
「ruby-lang docs Abbreviated Assignment」。
https://docs.ruby-lang.org/en/2.4.0/syntax/assignment_rdoc.html#label-Abbreviated+Assignment
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
。a
まだ持っています5
ます。
Rubyでアクセサを高速化するために使用されているそのメモ化パターン。
def users
@users ||= User.all
end
これは基本的に次のように変換されます。
@users = @users || User.all
したがって、このメソッドを初めて呼び出すときにデータベースを呼び出します。
このメソッドの今後の呼び出しは、@users
インスタンス変数の値を返すだけです。
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 を実行しても結果は同じです。