Почему безопасная навигация лучше, чем при использовании Rails?

Я читаю это. Какая польза от использования этого:

user&.address&.state

над

user.try(:address).try(:state)

Я все еще не понимаю.

Ответ 1

(1) &. обычно короче try(...)

В зависимости от сценария это может сделать ваш код более читаемым.

(2) &. является стандартным Ruby, в отличие от try

Метод try не определен в основной библиотеке Ruby, а скорее в библиотеке Rails. Когда вы не разрабатываете веб-приложение RoR, а вместо этого пишете, например. небольшие вспомогательные скрипты, это будет очень актуально. (Например, я предпочитаю Ruby над Bash.)

(3) &. упрощает отладку

Оператор безопасного обхода выдает ошибку, если вызывается несуществующий метод.

>> "s"&.glubsch
NoMethodError: undefined method `glubsch' for "s":String

Только на nil он будет проявлять снисходительность:

>> nil&.glubsch
=> nil

Метод try всегда будет возвращать nil.

>> "s".try(:glubsch)
=> nil

Обратите внимание, что это относится к самым последним версиям Ruby и Rails.

Теперь представьте сценарий, в котором существует метод с именем glubsch. Затем вы решите переименовать этот метод, но забудьте переименовать его в одном месте. (К сожалению, это может случиться с рубином...) С оператором безопасного обхода вы заметите ошибку почти сразу (как только эта строка кода будет выполнена в первый раз). Метод try, однако, с радостью предоставит вам nil, и вы получите сообщение об ошибке nil где-то ниже по течению при выполнении программы. Выяснить, откуда пришел такой nil, может быть сложно время от времени.

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

EDIT: Существует также вариант try! (с помехой), который ведет себя так же, как &. в этом отношении. Используйте это, если вам не нравится &..

(4) Что делать, если мне неважно, реализован ли метод?

Это было бы странно. Поскольку это будет неожиданным способом программирования, пожалуйста, сделайте это явным. Например, путем выделения двух случаев (реализованных или нет) с использованием respond_to? и отклонением от него.

(5) Как насчет try блочной формы?

Вместо имени метода блок можно передать в try. Блок будет выполнен в контексте получателя; и внутри блока не применяется смягчение. Таким образом, с помощью всего одного вызова метода он будет действовать так же, как &..

>> "s".try{ glubsch }
NameError: undefined local variable or method `glubsch' for "s":String

Для более сложных вычислений вы можете предпочесть эту блочную форму, вводя множество локальных переменных. Например. цепь

foo.try{ glubsch.blam }.try{ bar }.to_s

позволяет foo быть nil, но требует foo.glubsch для возврата значения nil. Опять же, вы можете сделать то же самое с оператором безопасного обхода в более сжатой форме:

foo&.glubsch.blam&.bar.to_s

Использование блочной формы try для сложных вычислений IMHO - запах кода, хотя, поскольку это затрудняет читаемость. Когда вам нужно реализовать сложную логику, введите локальные переменные с описательными именами и, возможно, используйте if для ветки от случая nil. Ваш код будет более удобным.

НТН!

Ответ 2

(6) Скорость

Безопасная навигация почти в 4 раза быстрее, чем использование метода try из activesupport

require 'active_support/all'
require 'benchmark'

foo = nil

puts Benchmark.measure { 10_000_000.times { foo.try(:lala) } }
puts Benchmark.measure { 10_000_000.times { foo&.lala } }

Выход

  1.310000   0.000000   1.310000 (  1.311835)
  0.360000   0.000000   0.360000 (  0.353127)