回答:
これはセーフナビゲーションオペレーターと呼ばれます。Ruby 2.3.0で導入され、Railsのメソッドと同様に、オブジェクトがnil
(undefined method for nil:NilClass
エラーを回避して)存在することを心配せずにオブジェクトのメソッドを呼び出すことができます。try
だからあなたは書くことができます
@person&.spouse&.name
の代わりに
@person.spouse.name if @person && @person.spouse
ドキュメントから:
my_object.my_method
これにより、my_methodメッセージがmy_objectに送信されます。任意のオブジェクトをレシーバーにすることができますが、メソッドの可視性によっては、メッセージを送信するとNoMethodErrorが発生する場合があります。
&を使用できます。レシーバを指定する場合、my_methodは呼び出されず、レシーバがnilの場合、結果はnilになります。その場合、my_methodの引数は評価されません。
注:@Santoshが明確かつ完全な回答を提供しましたが、背景を追加し、非インスタンス変数での使用に関する重要な注記を追加します。
これは「安全なナビゲーションオペレーター」と呼ばれます(「オプションのチェーンオペレーター」、「ヌル条件演算子」など)。マッツはそれを「孤独なオペレーター」と呼んでいるようです。それはされたのRuby 2.3で導入されました。ない場合にのみ、メソッドをオブジェクトに送信しますnil
。
# Call method `.profile` on `user` only if `user` is not `nil`
@user&.profile
# Equivalent to
unless @user.nil?
@user.profile
end
上記のコードはインスタンス変数を使用していることに注意してください。ローカル変数でセーフナビゲーション演算子を使用する場合は、ローカル変数が最初に定義されていることを確認する必要があります。
# `user` local variable is not defined previous
user&.profile
# This code would throw the following error:
NameError: undefined local variable or method `user' for main:Object
この問題を修正するには、ローカル変数が最初に定義されているかどうかを確認するか、nilに設定します。
# Option 1: Check the variable is defined
if defined?(user)
user&.profile
end
# Option 2: Define your local variable. Example, set it to nil
user = nil
user&.profile # Works and does not throw any errors
Railsにはtry
基本的に同じことをするメソッドがあります。send
内部でmethodを使用してメソッドを呼び出します。Matzはそれは遅いのでこれは組み込みの言語機能であるべきだと提案しました。
他の多くのプログラミング言語にも同様の機能があります。ObjectiveC、Swift、Python、Scala、CoffeeScriptなどです。ただし、一般的な構文は?.
(疑問符)です。しかし、この構文はRubyでは採用できませんでした。そのため?
、メソッド名で許可されたので、?.
シンボル系列は、すでに有効なRubyのコードです。例えば:
2.even?.class # => TrueClass
Rubyコミュニティが異なる構文を考え出す必要があったのはそのためです。これは、(活発な議論と異なるオプションを考慮した.?
、?
、&&
など)。ここにいくつかの考慮事項のリストがあります:
u.?profile.?thumbnails
u\profile\thumbnails
u!profile!thumbnails
u ? .profile ? .thumbnails
u && .profile && .thumbnails
# And finally
u&.profile&.thumbnails
構文を選択する際、開発者はさまざまなエッジケースを検討しましたが、この議論は非常に役に立ちます。オペレーターのすべてのバリアントとニュアンスを確認したい場合は、公式のRuby Issue Tracker に関するこの機能紹介のディスカッションを参照してください。
.?
他のオプションが検討&.
されましたが、選択されました!したがって、&.
機能します。
&.
ない.?
。私の答えを更新しました。ヘッドアップをありがとう!
user.?profile
必要がありますuser&.profile
(1文字の編集なので、自分で編集することはできません!)。
注意してください!安全なナビゲーションオペレーターは便利ですが、それを使用してロジックを変更するように騙すのも簡単です。フロー制御では使用しないことをお勧めします。例:
str = nil
puts "Hello" if str.nil? || str.empty?
# The above line is different than the below line
puts "Hello" if str&.empty?
最初の例では、str.nil?
返すtrue
とstr.empty?
原因、と呼ばれることはありませんputs
文が実行されます。ただし、2番目の例ではfalse str&.empty?
が返さnil
れ、puts
ステートメントは実行されません。
str.nil?
で(あなたが言うように)trueですが、これはstr.empty?
実際にはまったく呼び出されないことを意味します(つまり、||
演算子はこのように動作します)。あなたのステートメントの残りの部分は正しいです。
puts "hello" unless str&.present?
(現在のみレールですか?)に使用するのに完全に有効です
try!
する方法、ではないtry