Ruby アンパサンドを用いた安全参照演算子(&.)とは


はじめに

変数がnilの時、メソッドによってはエラーを起こすものがあったりします。

例えば、なんかの処理で値を配列に詰めたものをeachで回したりするときに、もしnilが入ってたりすると、処理が止まってエラーが出る。。なんてことが起こると困りますよね。

そんなときはガード節(関数や繰り返し処理の最初に例外を取り除くように実装する方法)を使ってnext if [変数].nil?とやって、nilを回避できたりするんですが、論理演算子を応用した別の方法があるときいて、メモしていきたいと思います。

アンパサンド(&)を用いた安全参照演算子

最初に結論から申しますと、[オブジェクト]&.[メソッド]というかたちで書きます。

例えば、

#&を使わないと
ary = [[1,2,3],nil,[5,6]]

ary.each do |element_ary|
  p element_ary.length
end

#=>

#3
#Traceback (most recent call last):
#   2: from test.rb:3:in `<main>'
#   1: from test.rb:3:in `each'
#test.rb:4:in `block in <main>': undefined method `length' for #nil:NilClass (NoMethodError)

#&を使うと
ary = [[1,2,3],nil,[5,6]]

ary.each do |element_ary|
  puts element_ary&.length
end

#=>

#3
#nil
#2

このように、エラーがおきません。

原理

実はこれ、論理演算子&&が関係しています。

一般的に、論理演算子は以下の特徴を持ってます。

・左から順に評価される
・論理式の真偽が決まると、残りの式は評価されない
・最後に評価された式の値が論理全体の値となる

つまり、[条件1] && [条件2]とあったとき、[条件2][条件1]が真のときにのみ、評価されます。[条件1]nilもしくはfalseであった場合、条件2を評価するまでもなく、論理演算子&&の結果はnilもしくはfalseになるからです。

[2020/10/27 追記]
コメント欄にて、条件1falseのときは使えないというご指摘をいただきましたので、修正します。失礼いたしました。。

これを応用して、上記の例を用いて説明すると、以下のように書けます。

ary = [[1,2,3],nil,[5,6]]

ary.each do |element_ary|
  p element_ary && element_ary.length
end

element_arynilが入ると[条件1]の時点で、論理演算子の処理が終わり、nilを返すので、[条件2]lengthメソッドにnilが渡ることはありません。

これを省略して以下のように、オブジェクトの後に&をつけることでも表現できるのが、安全参照演算子と呼ばれるものだったのです。

ary = [[1,2,3],nil,[5,6]]

ary.each do |element_ary|
  p element_ary&.length
end

おわりに

論理演算子の応用例ということでしたが、あたまいいなあと思いました。