Safe Navigation Operator(&.)
정의
Safe Navigation Operator(&.)는 Ruby 2.3의 신기능으로 메서드 호출 시 .(dot) 앞에 &를 붙이면 수신 객체가 nil이어도 NoMethodError가 발생하지 않고 nil을 반환하는 기능이다. 사용 시 &와 .을 세트로 사용해야하며 &만 단독으로 사용할 수는 없다.
한국어로도 표현하고 싶은데 적당한 단어가 없는 것 같다. 참고한 블로그를 보니 일본에서는 ぼっち演算子(의역: 외로운 연산자)라고 부른다고 한다.
예시
예를 들어 아래와 같은 코드가 있다고 가정해보자.
@person.spouse.name if @person && @person.spouse
Safe Navigation Operator(&.)를 사용하면 위 코드를 아래와 같이 변경할 수 있다.
@person&.spouse&.name
배열에서는 다음과 같이 사용할 수 있다.
>> foo = {a: 1}
=> {:a=>1}
>> foo[:a]
=> 1
>> foo&.[](:a)
=> 1
>> nil&.[](:a)
=> nil
try 메서드와의 차이
Safe Navigation Operator(&.)는 일반적으로 레일즈의 try 메서드와 비교된다. 둘 다 메서드 호출 시 수신 객체가 nil이어도 NoMethodError를 발생시키지 않고 nil을 돌려주는 기능을 제공한다.
# Safe Navigation Operator와 try 모두 수신 객체가 nil이어도 NoMethodError가 아닌 nil을 반환한다.
>> nil&.my_method
=> nil
>> nil.try(:my_method)
=> nil
다만 수신 객체가 nil이 아닌 경우 메서드 호출 시 차이가 생긴다. Safe Navigation Operator(&.)는 수신 객체가 nil이 아니기 때문에 메서드를 호출하려고 하지만 my_method는 존재하지 않기 때문에 NoMethodError가 발생한다. 하지만 try 메서드는 오류를 발생시키지 않고 nil을 반환한다.
>> "foo"&.my_method
Traceback (most recent call last):
1: from (irb):34
NoMethodError (undefined method `my_method` for "foo":String)
Did you mean? method
>> "foo".try(:my_method)
=> nil
편리하다고 생각할 수 있겠지만 try 메서드는 수신 객체에 해당 메서드가 없어도 nil을 돌려주니 디버깅이 어렵다는 문제가 제기되었다. 그 후 try!라는 메서드가 rails4부터 도입되었고 루비도 버전 2.3부터 try! 메서드와 동일한 기능을 하는 Safe Navigation Operator(&.)를 도입하였다.
# try! 는 Safe Navigation Operator와 완벽히 같다.
>> "foo"&.my_method
Traceback (most recent call last):
1: from (irb):36
NoMethodError (undefined method `my_method` for "foo":String)
Did you mean? method
>> "foo".try!(:my_method)
Traceback (most recent call last):
2: from (irb):37
1: from (irb):37:in `rescue in irb_binding'
NoMethodError (undefined method `my_method` for "foo":String)
참고 자료 및 사이트
- https://stackoverflow.com/questions/36812647/what-does-ampersand-dot-mean-in-ruby
- https://en.wikipedia.org/wiki/Safe_navigation_operator
- https://negabaro.github.io/archive/ruby-safe-navigation-operator
- https://api.rubyonrails.org/v4.2/classes/Object.html#method-i-try