Was macht &. (kaufmännisches Und-Punkt) bedeutet in Ruby?

Antworten:

205

Es wird als sicherer Navigationsoperator bezeichnet. Mit der in Ruby 2.3.0 eingeführten Methode können Sie Methoden für Objekte aufrufen, ohne befürchten zu müssen, dass das Objekt ähnlich ist nil( undefined method for nil:NilClassFehler vermeiden ), ähnlich der tryMethode in Rails .

So können Sie schreiben

@person&.spouse&.name

anstatt

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

Aus den Dokumenten :

my_object.my_method

Dadurch wird die Nachricht my_method an my_object gesendet. Jedes Objekt kann ein Empfänger sein, aber abhängig von der Sichtbarkeit der Methode kann das Senden einer Nachricht einen NoMethodError auslösen.

Sie können & verwenden. Um einen Empfänger zu bestimmen, wird my_method nicht aufgerufen und das Ergebnis ist null, wenn der Empfänger null ist. In diesem Fall werden die Argumente von my_method nicht ausgewertet.

Santhosh
quelle
13
Eigentlich funktioniert es wie die try!Methode, nichttry
Grzegorz
58

Hinweis: Auch wenn @Santosh eine klare und vollständige Antwort gegeben hat, möchte ich weitere Hintergrundinformationen hinzufügen und einen wichtigen Hinweis zur Verwendung mit Nichtinstanzvariablen hinzufügen .


Es wird als " sicherer Navigationsoperator " bezeichnet (auch bekannt als "optionaler Verkettungsoperator", "nullbedingter Operator" usw. ). Matz scheint es "einsamer Operator" zu nennen. Es wurde in Ruby 2.3 eingeführt . Es sendet eine Methode nur dann an ein Objekt, wenn dies nicht der Fall ist nil.

Beispiel:

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

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

"Randfall" mit lokalen Variablen:

Bitte beachten Sie, dass der obige Code Instanzvariablen verwendet. Wenn Sie einen sicheren Navigationsoperator mit lokalen Variablen verwenden möchten, müssen Sie zuerst überprüfen, ob Ihre lokalen Variablen definiert sind.

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

Um dieses Problem zu beheben, überprüfen Sie, ob Ihre lokale Variable zuerst definiert wurde, oder setzen Sie sie auf Null:

# 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

Methodenhintergrund

Rails hat eine tryMethode, die im Grunde das Gleiche tut. Es verwendet sendintern eine Methode, um eine Methode aufzurufen. Matz schlug vor, dass es langsam ist und dies eine integrierte Sprachfunktion sein sollte.

Viele andere Programmiersprachen haben ähnliche Funktionen: Ziel C, Swift, Python, Scala, CoffeeScript usw. Eine gebräuchliche Syntax ist jedoch ?.(Fragepunkt). Diese Syntax konnte jedoch von Ruby nicht übernommen werden. Da ?in Methodennamen erlaubt war und somit die ?.Symbolfolge bereits ein gültiger Ruby-Code ist. Beispielsweise:

2.even?.class  # => TrueClass

Deshalb musste sich die Ruby-Community eine andere Syntax einfallen lassen. Es war eine aktive Diskussion und verschiedene Optionen in Betracht gezogen wurden ( .?, ?, &&, etc.). Hier ist eine Liste einiger Überlegungen:

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

# And finally
u&.profile&.thumbnails

Bei der Auswahl der Syntax haben sich die Entwickler verschiedene Randfälle angesehen, und die Diskussion ist sehr nützlich. Wenn Sie alle Varianten und Nuancen des Bedieners durchgehen möchten, lesen Sie bitte diese Diskussion zur Einführung in den offiziellen Ruby Issue Tracker.

Usbekjon
quelle
Was ist '.?' ? Ich denke, es wurde entschieden, dass diese Syntax nicht verwendet werden kann. Ich kann nur '&' bekommen. arbeiten.
Keith Bennett
2
Genau wie ich schrieb .?und andere Optionen in Betracht gezogen wurden, wurde aber &.gewählt! Also wird nur &.funktionieren.
Usbekjon
Oh, sorry, ich habe bis zum Ende nicht gründlich gelesen. Wäre es nicht besser, wenn die Beispiele die richtige Syntax hätten?
Keith Bennett
@ KeithBennett Ich verstehe, was du meinst. In meinem ersten Beispiel hatte ich einen Tippfehler. Du hast recht, es muss sein &.und nicht .?, mein schlechtes. Meine Antwort wurde aktualisiert. Danke für die Warnung!
Usbekjon
@ Usbekjon Es gibt immer noch einen Tippfehler im Edge-Fallbeispiel (Option 1): user.?profilesollte sein user&.profile(konnte es nicht selbst bearbeiten, da es nur eine 1-Zeichen-Bearbeitung ist!).
Yanis Vieilly
7

Sei vorsichtig! Obwohl der sichere Navigationsoperator praktisch ist, kann es auch einfach sein, sich dazu zu verleiten, Ihre Logik damit zu ändern. Ich empfehle, die Verwendung in der Flusskontrolle zu vermeiden. Beispiel:

str = nil

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

Im ersten Beispiel wird str.nil?zurückgegeben trueund str.empty?nie aufgerufen, wodurch die putsAnweisung ausgeführt wird. Im zweiten Beispiel jedoch str&.empty?kehrt nildie Falsey ist, und die putsAnweisung wird nie ausgeführt.

Thomas Deranek
quelle
Interessant, obwohl technisch gesehen Ihre erste Aussage str.nil?wahr ist (wie Sie sagen), was bedeutet, str.empty?dass sie überhaupt nicht aufgerufen wird (so funktioniert der ||Operator). Der Rest Ihrer Aussage ist richtig.
Ollie Bennett
1
Oh guter Fang. Ich bin mir nicht sicher, wie ich das verpasst habe. Ich werde meinen Beitrag korrigieren. Danke dir!
Thomas Deranek
2
Es ist wahr, dass es viel einfacher ist, die falsche Logik zu verwenden, aber Sie überprüfen hier verschiedene Dinge. Die zweite Zeile entspricht, wenn str && str.empty? nicht null || leer. Der sichere Navigationsoperator ist weiterhin für die Flusskontrolle puts "hello" unless str&.present?(Schienen nur für die vorliegende Methode) gültig
Sampson Crowley
1

es wird für Null-Check verwendet, wie zum Beispiel in Kotlin und Swift; mit Objekt -> Swift und Kotlin

model = car?.model

Dieses Modell kann null (Swift) oder null (Kotlin) sein, wenn wir den Modellwert in der Fahrzeugklasse nicht definiert haben. Wir verwenden dieses kaufmännische Und anstelle des Fragezeichens in Ruby

model = car&.model

Wenn Sie car.model ohne kaufmännisches Und verwenden und das Modell Null ist, kann das System nicht weiter ausgeführt werden.

Umut ADALI
quelle