HIDE5419'S BLOG

1954年生まれ フリーランス活動を始めた駆け出しエンジニアです 学んだことをメインにアウトプットしていきます

「||=」(or equals) について

「||=」(or equals) について、きちんと理解をしておきたかったのでRuby on Rails チュートリアルの記事を参考に記録しました。

この「||=」(or equals) という代入演算子Rubyで広く使われているイディオムであり、Ruby開発者を志すならこの演算子に習熟することが重要です。
or equalsという概念は一見不思議にみえますが、他のものになぞらえて考えれば難しくありません。

多くのコンピュータプログラムでは、次のような記法で変数の値を1つ増やすことができます。

x = x + 1

そして、Ruby およびC、C++PerlPythonJavaなどの多くのプログラミング言語では、上の演算を次のような短縮形で表記することもできます。

x += 1

他の演算子についても同様の短縮形が利用できます。

$ rails console
>> x = 1
=> 1
>> x += 1
=> 2
>> x *= 3
=> 6
>> x -= 8
=> -2
>> x /= 2
=> -1

いずれの場合も、●という演算子があるときの「x = x ● y」と「x ●= y」の動作は同じです。

Rubyでは、「変数の値がnilなら変数に代入するが、nilでなければ代入しない (変数の値を変えない)」という操作が非常によく使われます。
or演算子 || を使えば、次のように書くことができます。

>> @foo
=> nil
>> @foo = @foo || "bar"
=> "bar"
>> @foo = @foo || "baz"
=> "bar"

nilの論理値はfalseになるので、@fooへの最初の代入「nil || "bar"」の評価値は"bar"になります。
同様に、2つ目の代入「@foo || "baz"」("bar" || "baz"など) の評価値は"bar"になります。
Rubyでは、nilとfalseを除いて、あらゆるオブジェクトの論理値がtrueになるように設計されています。
さらにRubyでは、||演算子をいくつも連続して式の中で使う場合、項を左から順に評価し、最初にtrueになった時点で処理を終えるように設計されています。

なお、このように||式を左から右に評価し、演算子の左の値が最初にtrueになった時点で処理を終了するという評価法を短絡評価 (short-circuit evaluation) と呼びます。

論理積の&&演算子も似たような設計になっていますが、項を左から評価して、最初にfalseになった時点で処理を終了する点が異なります。

上記の演算子をコンソールセッション上で実際に実行して比較してみると、@foo = @foo || "bar"はx = x O yに該当し、Oが||に置き換わっただけであることがわかります。

x = x + 1 -> x += 1
x = x * 3 -> x *= 3
x = x - 8 -> x -= 8
x = x / 2 -> x /= 2
@foo = @foo || "bar" -> @foo ||= "bar"
これで「@foo = @foo || "bar"」は「@foo ||= "bar"」と等価であることが理解できます。

この記法をcurrent_userの文脈
@current_user = @current_user || User.find_by(id: session[:user_id])
で使うと

次のような簡潔なコードになります。
@current_user ||= User.find_by(id: session[:user_id])



補足:
技術的には、「@foo || @foo = "bar"」と書いた場合、Rubyの内部では実際にすべての項が評価されます (||が左辺にある点に注意)。
これは@fooがnilやfalseでない場合に、無駄な代入を避ける必要があるためです。
しかしこの式の動作では||=記法の動作と同じにならず、説明上不都合なので、上の解説では@foo = @foo || "bar" という式を用いて説明しました。