Hyurakuのエンジニア日誌

SE出身Webエンジニアのブログ

注意したいrubyの演算子||=の使い方#1

最近Ruby演算子||=を使用していて便利だと思っていたが
特に式の左辺について注意しなければいけない点があるようなので今から解説。

  1. ||=とは

ドキュメント(https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html)より参照。

文法
式1 op= 式2     # 式1は通常の代入の左辺のいずれか
--< 省略 >--
この形式の代入は
式1 = 式1 op 式2
と評価されます。ただし、op が &&, || の場合には、
式1 op (式1 = 式2)
と評価されます。この違いは属性参照のときに
obj.foo ||= true
が、
obj.foo = obj.foo || true
でなく
obj.foo || (obj.foo = true)
と呼ばれることを示します。(obj.foo= は obj.foo の結果によって呼ばれないかも知れません)  

なんとなく使い方は分かるがobj.foo= は obj.foo の結果によって呼ばれないかもというのがよくわからなかったので簡単なコードを書いてみた。

  1. 実際に書いてみた。

・式1(左辺)が未定義の場合
実際に下のコードを動かしてみる。

index.rb

def greeting(time)
  p 'ready to greet'
  if time == 'morning'
    return 'Good Morning'
  elsif time == 'day'
    return 'Hello'
  end
end

say_something ||=greeting('day')

p say_something

このときsay_somethigはまだ未定義。 実際に動かしてみた。

ruby index.rb
>"ready to greet"
>"Hello"

確認できることは2つ。 - greetingメソッドが実行されたこと。 - 未定義だったsay_somethingが'Hello'と定義されたこと。

・式1(左辺)が定義済の場合
今度は上のコードに一行追加した。

def greeting(time)
  p 'ready to greet'
  if time == 'morning'
    return 'Good Morning'
  elsif time == 'day'
    return 'Hello'
  end
end

say_something = 'Bye' #追加しました
say_something ||=greeting('day')

p say_something

このときsay_somethigは''Bye'と定義された。

実際に動かしてみました。

ruby index.rb
>"Bye"

確認できることは2つ。 - greetingメソッドが実行されなかったこと。 - Byeと定義されたsay_somethingは'Bye'のままだったこと。

これからは||=を使用する際には左辺の定義に注意して書く。