2013-10-25 10 views
10

Betrachten Sie den folgenden irb Ausschnitt aus einer frisch gestarteten Sitzung:Seltsame Bedeutung von || und || = in Ruby (2.0, 1.9.3, 1.7.4 jruby)

irb:01> baz   # => NameError, baz is not defined 
irb:02> baz || baz = 0 # => NameError, baz is not defined 
irb:03> baz   # => nil 

baz war eine nicht definierte Variable und versucht, sie zu bewerten produzierten a NameError. Irgendwie wurde nach dieser Operation jedoch baz definiert und hat einen Wert von nil. Scheinbar wurde der Variable nil die Variable baz zugewiesen, obwohl niemand (explizit) darum gebeten hat. Gibt es einen zugrunde liegenden Sprachgrund, warum dieses Verhalten wünschenswert ist?

Was ist die Regel, die dieses Verhalten und andere ähnlich verwirrend Konstrukte, wie diese erklärt:

irb:04> true if foo   # => NameError 
irb:05> foo     # => NameError; name still undefined 
irb:06> foo = (true if foo) # => nil 
irb:07> foo     # => nil; name defined as nil 
irb:08> true || i = 0 || j = 2 # => i and j are nil; || appears nonlazy 
irb:09> raise || quux = 1  # => RuntimeError, quux is nil 
+3

Sie verwenden nicht wirklich '|| =' in irgendeinem Ihrer Beispiele, der Fragetitel ist ein wenig irreführend – nzifnab

+0

Noch seltsamer: '>> spam # => NameError; >> spam || = "Eier" # => "Eier"; >> spam # => "Eier" '. Inkonsistent. – iamnotmaynard

+0

mögliches Duplikat von [Verwechslung mit der Zuweisungsoperation innerhalb des Fallacys \ 'if \' block] (http://stackoverflow.com/questions/15183576/confusion-with-the-assignment-operation-inside-the-fallacy-if -block) –

Antwort

9

Ich weiß nicht, ob es wünschenswert ist, aber es kommt von, wie Ruby-parst den Code. Wenn Sie über einen Code verfügen, der eine lokale Variable zuweist, wird dieser lokalen Variablen nil zugewiesen, auch wenn dieser Code nicht ausgewertet wird. In Ihrem Code Zeile 2:

baz || baz = 0 

die ersten baz einen Fehler zurückgegeben, da keine solche Variablen zugewiesen wurden. Daraus ergibt sich die Zuordnung baz = 0, dass es wurde nicht bewertet folgt, aber dennoch war es analysiert, so im Kontext zu folgen, eine lokale Variable baz erstellt wurde und auf nil initialisiert.

Mit Ihrem zweiten Codeblock wird foo während true if foo und foo nicht zugewiesen. Danach hat foo = (true if foo) eine Zuordnung zu foo, so dass, obwohl (true if foo) vor der Zuweisung von foo ausgewertet wird, ein Fehler in dieser Zeile nicht ausgelöst wird.

+1

Meinen Kommentar löschen, da du deine Antwort korrigiert hast ;-) Jetzt ist es korrekt, die Zuweisung zu baz wird ** nicht ** durchgeführt, aber wenn Ruby ** Parser ** eine Zuweisung erkennt, weist er einen Platz dafür zu es und setzt auf "Null". –

+0

@DavidUnric Sie haben vielleicht schon etwas zu meiner Antwort gesagt, aber jetzt, ich denke nicht, dass Ihr Kommentar irgendwelche Informationen hinzufügt, die über meine Antwort hinausgehen. – sawa