В чем разница между `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.