Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
14
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

@yuya_takeyama

Safe Navigation Operator で呼ばれるメソッドの引数はレシーバが nil なら評価されない

タイトルの通りです。

Safe Navigation Operator に関するコミット を追いかけていると、ドキュメント中に興味深い一文が見つかりました。

You may use &. to designate a receiver, then my_method is not invoked and the result is nil when the receiver is nil. In that case, the arguments of my_method are not evaluated.

これは例えば obj&.my_method(arg) というメソッド呼び出しを行った時、 objnil だったら my_method への引数である arg は評価されない、ということです。

試してみる

早速試してみました。

オブジェクトに対して正しくメソッドを呼び出せたとき

safe1.rb
class Foo
  def my_method(s)
    "Foo#my_method is called with \"#{s}\""
  end
end

def arg
  puts "arg is evaluated"
  "m"
end

obj = Foo.new
puts obj&.my_method(arg)
$ ruby safe1.rb
arg is evaluated
Foo#my_method is called with "m"

obj.my_method の結果が出力される前に、arg が評価されていることがわかります。
何の違和感もありません。

レシーバのオブジェクトにメソッドが存在しなかったとき

safe2.rb
class Foo
end

def arg
  puts "arg is evaluated"
  "m"
end

obj = Foo.new
puts obj&.my_method(arg)
$ ruby safe2.rb
arg is evaluated
safe.rb:10:in `<main>': undefined method `my_method' for #<Foo:0x007fe859807020> (NoMethodError)
Did you mean?  method

NoMethodError が発生する前に arg が評価されていることがわかります。
これも特に違和感のない挙動です。

レシーバが nil だったとき

そしていよいよドキュメントに記載されているケースです。

safe3.rb
def arg
  puts "arg is evaluated"
  "m"
end

obj = nil
puts obj&.my_method(arg)
$ ruby safe3.rb

putsnil が渡されることで空行を出力しますが、arg は評価されていないことがわかります。

どういうときにうれしいか

これはやはり引数の評価に時間がかかるような場合、不要な評価を行わない分だけ実行時間を節約できます。

foo&.bar(some_heavy_computation_result)

この some_heavy_computation_result は何か重い処理を行うメソッドだったとして、foonil なら不要であるところのその呼び出しを省略してくれます。
ActiveSupportObject#try! に比べて高速、という記事も書きましたが、これは通常のライブラリでは実現できない最適化です。
逆に言うとレシーバが nil であろうと引数が評価されることを期待していると、そのようには動かないので注意が必要です。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
14
Help us understand the problem. What are the problem?