В чем разница между `try` и `&.'(оператор безопасной навигации) в Ruby

вот мой код:

class Order < Grape::Entity
  expose :id { |order, options| order.id.obfuscate }
  expose :time_left_to_review do |order, options|
    byebug
    order&.time_left_to_review # ERROR
  end
  expose :created_at { |order, options| order.last_transition.created_at }
end

# NoMethodError Exception: undefined method `time_left_to_review' for #<Order:0x007f83b9efc970>

Я думал &. ярлык для .try но я думаю, что ошибался. Может ли кто-нибудь указать мне правильное направление относительно того, чего мне не хватает?

Я чувствую, что это не связано с Руби. Может, виноград? Хотя я не понимаю, как это может быть.

4 ответов


&. работы как #try!, а не #try.

а вот описание #try! (от документация):

то же самое, что и #try, но вызовет исключение NoMethodError, если получение не равно нулю и не реализован проверенный метод.

таким образом, в основном это избавляет вас от вызова метода на nil, но если объект представлен, он попытается вызвать свой метод, как обычно.

цитата из Документация Rails, и поэтому важно подчеркнуть что Ruby не предоставляет #try, это рельсы, или, точнее, ActiveSupport. Пока безопасный оператор навигации &. - языковая функция, представленная в Ruby 2.3.0.


на try метод игнорирует много вещей, он просто дает ему шанс и называет его днем, если что-то не получается.

на & опция условной навигации будет только блокировать вызовы nil объекты. Все остальное считается действительным и будет действовать с полными последствиями, включая исключения.


согласен с @Redithion комментарий

Оператор Безопасной Навигации (&.) in Ruby

сценарий

представьте, что у вас есть account С owner и вы хотите получить владельца address. Если вы хотите быть в безопасности и не рисковать нулевой ошибкой, вы напишете что-то вроде следующего.

if account && account.owner && account.owner.address
...
end

это действительно многословно и раздражает для ввода. ActiveSupport включает в себя try метод, который имеет аналогичное поведение (но с несколько ключевых отличий, которые будут обсуждаться позже):

if account.try(:owner).try(:address)
...
end

он выполняет то же самое - он либо возвращает адрес или nil если некоторое значение вдоль цепи nil. Первый пример также может возвращать false, если, например,owner имеет значение false.

С помощью &.

мы можем переписать предыдущий пример с использованием безопасная навигация оператор:

account&.owner&.address

примеры

давайте сравним все три подхода более подробно.

account = Account.new(owner: nil) # account without an owner

account.owner.address
# => NoMethodError: undefined method `address' for nil:NilClass

account && account.owner && account.owner.address
# => nil

account.try(:owner).try(:address)
# => nil

account&.owner&.address
# => nil

пока никаких сюрпризов. Что, если ... --8--> и false (маловероятно, но не невозможно в захватывающем мире дерьмового кода)?

account = Account.new(owner: false)

account.owner.address
# => NoMethodError: undefined method `address' for false:FalseClass `

account && account.owner && account.owner.address
# => false

account.try(:owner).try(:address)
# => nil

account&.owner&.address
# => undefined method `address' for false:FalseClass`

вот первый сюрприз -&. синтаксис пропускает только nil но признает ложными! Это не совсем эквивалентно s1 && s1.s2 && s1.s2.s3 синтаксис.

что делать, если владелец присутствует, но не отвечает address?

account = Account.new(owner: Object.new)

account.owner.address
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>

account && account.owner && account.owner.address
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`

account.try(:owner).try(:address)
# => nil

account&.owner&.address
# => NoMethodError: undefined method `address' for #<Object:0x00559996b5bde8>`

ниже пример сбивает с толку и nil&.nil? должен возвратить true.

будьте осторожны при использовании &. оператор и проверка на nil значения. Рассмотрим следующий пример:

nil.nil?
# => true

nil?.nil?
# => false

nil&.nil?
# => nil

ссылки: здесь


Я прихожу на вечеринку немного поздно здесь, я уже рассказывал, как это работает, но я хотел добавить что-то, что другие ответы не закрыл.

ваш вопрос спрашивает, в чем разница между try и &. на Рубин. Руби-ключевое слово здесь.

самая большая разница в том, что try не существует в Ruby, это метод, предоставляемый Rails. вы можете увидеть это или себя, если вы сделаете что-то подобное в консоль рельсов:

[1, 2, 3].try(:join, '-')
#=> "1-2-3" 

однако, если вы сделаете то же самое в консоли irb, вы получите:

[1, 2, 3].try(:join, '-')
NoMethodError: undefined method `try' for [1, 2, 3]:Array

на &. является частью стандартной библиотеки Ruby и поэтому доступен в любом проекте Ruby, а не только Rails.