Что значит &. (амперсанд) в Ruby?

Я столкнулся с этой строкой кода ruby. Что означает &. в этом?

@object&.method

Ответ 1

Это называется оператор безопасной навигации. Представленный в Ruby 2.3.0, он позволяет вызывать методы для объектов, не беспокоясь о том, что объект может иметь значение nil (undefined method for nil:NilClass ошибки undefined method for nil:NilClass), аналогично методу try в Rails.

Так что вы можете написать

@person&.spouse&.name

вместо

@person.spouse.name if @person && @person.spouse

Из документов:

my_object.my_method

Это отправляет сообщение my_method my_object. Любой объект может быть получателем, но в зависимости от видимости метода отправка сообщения может вызвать ошибку NoMethodError.

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

Ответ 2

Примечание. Несмотря на то, что @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 для вызова метода. Мац предложил, что он медленный, и это должна быть встроенная функция языка.

Многие другие языки программирования имеют схожую особенность: Objective C, Swift, Python, Scala, CoffeeScript и т.д. Однако общий синтаксис ?. (question dot). Но этот синтаксис не был принят 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.

Ответ 3

Будьте осторожны! Хотя оператор безопасной навигации удобен, он также может легко обмануть себя и изменить свою логику. Я рекомендую избегать использования этого в управлении потоком. Пример:

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. Во втором примере, однако, str&.empty? возвращает nil, что неверно, и оператор puts никогда не выполняется.

Ответ 4

он используется для проверки на ноль, например, в kotlin и swift; с объектом → Свифт и Котлин

model = car?.model

эта модель может быть nil (Swift) или null (Kotlin), если мы не определили значение модели в классе автомобиля. мы используем этот амперсанд вместо знака вопроса в рубине

model = car&.model

если использовать car.model без амперсанда и если модель равна нулю, система не сможет продолжить работу.