web-dev-qa-db-fra.com

Que fait &. (esperluette) signifie en Ruby?

Je suis tombé sur cette ligne de code Ruby. Qu'est-ce que &. signifie en cela?

@object&.method
116
Sami

C'est ce qu'on appelle l'opérateur de navigation sécurisée. Introduit dans Ruby 2.3.0, il permet d’appeler des méthodes sur des objets sans s’inquiéter du fait que cet objet peut être nil (éviter une erreur undefined method for nil:NilClass), similaire à la méthode try dans Rails

Donc tu peux écrire

@person&.spouse&.name

au lieu de

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

De la Docs :

my_object.my_method

Cela envoie le message my_method à my_object. Tout objet peut être un récepteur mais en fonction de la visibilité de la méthode l'envoi d'un message peut déclencher une erreur NoMethodError.

Vous pouvez utiliser &. pour désigner un destinataire, my_method n'est pas appelé et le résultat est nul lorsque le récepteur est nul. Dans ce cas, le Les arguments de my_method ne sont pas évalués.

144
Santhosh

Note: Même si @Santosh a donné une réponse claire et complète, je voudrais ajouter un peu plus de fond et ajouter une note important concernant son utilisation avec des variables autres que des instances.


Il s'appelle " Opérateur de navigation sécurisée } _" (alias "Opérateur de chaînage facultatif", "Opérateur Null-conditionnel", etc.). Matz semble l'appeler "opérateur solitaire". C'était introduit dans Ruby 2.3 . Il envoie une méthode à un objet uniquement s'il ne s'agit pas de nil.

Exemple:

# Call method `.profile` on `user` only if `user` is not `nil`
@user&.profile

# Equivalent to
unless @user.nil?
  @user.profile
end

"Edge case" avec variables locales:

Veuillez noter que le code ci-dessus utilise des variables d'instance. Si vous souhaitez utiliser un opérateur de navigation sécurisé avec des variables locales, vous devez d'abord vérifier que vos variables locales sont définies.

# `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

Pour résoudre ce problème, vérifiez si votre variable locale est définie en premier ou définissez-la sur 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

Fond de méthode

Rails a la méthode try qui fait fondamentalement la même chose. Il utilise la méthode send en interne pour appeler une méthode. Matz suggère que c'est lent et que cela devrait être une fonctionnalité de langage intégrée.

De nombreux autres langages de programmation ont des fonctionnalités similaires: Objective C, Swift, Python, Scala, CoffeeScript, etc. Cependant, une syntaxe courante est ?. (point de question). Mais, cette syntaxe n'a pas pu être adoptée par Ruby. Étant donné que ? était autorisé dans les noms de méthode et que, par conséquent, la séquence de symboles ?. est déjà un code Ruby valide. Par exemple:

2.even?.class  # => TrueClass

C'est pourquoi la communauté Ruby devait proposer une syntaxe différente. C’était une discussion active et différentes options ont été envisagées (.?, ?, &&, etc.). Voici une liste de quelques considérations:

u.?profile.?thumbnails
u\profile\thumbnails
u!profile!thumbnails
u ? .profile ? .thumbnails
u && .profile && .thumbnails

# And finally
u&.profile&.thumbnails

Tout en choisissant la syntaxe, les développeurs ont examiné différents cas Edge et la discussion est très utile. Si vous voulez passer en revue toutes les variantes et nuances de l'opérateur, veuillez vous reporter à discussion d'introduction de cette fonctionnalité sur l'outil de suivi des problèmes Ruby officiel.

46
Uzbekjon

Se méfier! Bien que l’opérateur de navigation sûr soit pratique, il peut également être facile de vous inciter à changer de logique avec lui. Je recommande d'éviter son utilisation dans le contrôle de flux. Exemple:

str = nil

puts "Hello" if str.nil? || str.empty?
# The above line is different than the below line
puts "Hello" if str&.empty?

Dans le premier exemple, str.nil? renvoie true et str.empty? n'est jamais appelé, ce qui entraîne l'exécution de l'instruction puts. Cependant, dans le deuxième exemple, str&.empty? renvoie nil, qui est falsey, et l'instruction puts n'est jamais exécutée.

3
Thomas Deranek

il est utilisé pour un contrôle nul, comme dans kotlin et Swift Par exemple; avec Object -> Swift et Kotlin

model = car?.model

ce modèle peut être nil (Swift) ou nul (Kotlin) si nous n'avons pas défini la valeur du modèle dans la classe car .

model = car&.model

si vous utilisez car.model sans esperluette et si model est égal à zéro, le système ne peut pas continuer à fonctionner.

1
Umut ADALI