2010-02-18 6 views
13

Was geht hier vor? Was ist der feine Unterschied zwischen den beiden Formen von "außer"?In Ruby Warum wird `foo = true, wenn nicht definiert? (Foo)` machen Sie die Aufgabe?

> irb(main):001:0> foo = true unless defined?(foo) 
=> nil 
irb(main):002:0> unless defined?(fooo) ; fooo = false ; end 
=> false 

thx

+0

Welche Version von Ruby verwenden Sie? – bta

+1

Mit all dem Gerede über die Zuweisung von Variablen, wenn sie nicht bereits definiert sind, fühle ich mich gezwungen, darauf hinzuweisen, dass 'foo || = true' das Gleiche bewirkt (und immer' true' zurückgibt). –

+1

@Allison R. Nicht wenn 'foo' definiert ist, aber falsch. – FMc

Antwort

15

Offenbar erstellt Ruby lokale Variable bei der Parse-Zeit setzen sie auf nil, so dass es definiert ist und dies erfolgt, ob der Code ausgeführt wird oder nicht.

Wenn der Code in der ersten Zeile ausgewertet wird, führt er den Zuweisungsteil nicht aus, da foo auf gesetzt ist. Da in der zweiten Zeile fooo noch nicht analysiert wurde, gibt defined?nil zurück, wodurch der Code innerhalb des Blocks ausgeführt und zugewiesen wird fooo.

Als Beispiel können Sie dies versuchen:

if false 
    foo = 43 
end 
defined? foo 
=> "local-variable" 

Dieses wird von einem Forum post in rubin Forum genommen wird.

+0

Ausgezeichnetes Beispiel - sollte darüber nachdenken, das Problem weiter zu vereinfachen. Vielen Dank. – farhadf

+0

gute Erklärung des komplexen Verhaltens –

-1

Nun .. Eine Form ist ein Block und ein Formular nicht. Der zweite Teil, der Block, gibt die letzte ausgewertete Aussage zurück. Der erste .. Hm .. Ich weiß nicht genau, was es macht.

+0

-1 Dies betrifft keine Blöcke. –

-1

In Ruby 1.8.7:

foo = true unless defined?(foo) 
p foo # => nil 

unless defined?(fooo); fooo = true; end 
p foo # => nil 

ich für das Verhalten keine Erklärung haben Sie sehen.

+0

'fooo' (im Gegensatz zu' foo') ist wahr. –

2
irb(main)> foo = true unless defined?(Integer) 
=> nil 
irb(main)> foo = true unless defined?(thisIsUndefined) 
=> true 

Ihr erster Block zurückkehrt nil, weil die Art und Weise es Blätter 2 Optionen geschrieben:

  • foo ist nicht definiert -> assign wahr
  • foo definiert ist -> nichts tun

Hier muss foo definiert werden, wenn die Linie ausgewertet wird. Somit passiert nichts und nil wird zurückgegeben.

irb(main)> unless defined?(Integer) ; fooo = false ; end 
=> nil 
irb(main)> unless defined?(thisIsUndefined) ; fooo = false ; end 
=> false 

Ihr zweiter Block funktioniert genauso wie Ihr erster Block. Wenn fooo nicht definiert ist, wird der Block eingegeben und fooo wird auf false gesetzt. Das Ergebnis der letzten Zeile des Blocks ist der Rückgabewert des Blocks, also der false, den Sie sehen. Wenn fooo existiert, dann wird der Block übersprungen und nichts passiert, daher gibt es nichts zurückzugeben, daher die nil.

Basierend auf Ihrem Code würde ich sagen, dass foo definiert wurde, als dieser Code ausgeführt wurde und fooo nicht war (Testcode wurde in Ruby 1.8.6 generiert). Wenn Sie vor dem Ausführen dieses Codes keines dieser Elemente definiert haben, haben Sie möglicherweise ein Element namens foo, das standardmäßig definiert ist (überprüfen Sie defined?(foo) selbst). Versuchen Sie es mit einem anderen Namen und sehen Sie, ob Sie die gleichen Ergebnisse erhalten.

Edit:

irb(main)> defined?(bar) 
=> nil 
irb(main)> bar = true unless defined?(bar) 
=> nil 
irb(main)> defined?(bar) 
=> "local-variable" 

Offenbar defined?() zurückkehrt wahr, da es bereits bar (am Anfang der Zeile) gesehen hat, auch wenn Sie noch im Prozess der Definition es sind.

1

In erster Instanz rufen Sie foo in der Zuweisungsanweisung auf. Vielleicht wird dies verdeutlichen:

bar = if true 
     puts bar.class 
     else 
     puts "not reached" 
     end 
NilClass 
=> nil 

baz = if true 
     puts baz.class 
     42 
     else 
     puts "not reached" 
     end 
NilClass 
=> 42 
12

ist mit etwas Beginnen wir einfacher:

# z is not yet defined 
irb(main):001:0> defined?(z) 
=> nil 

# Even though the assignment won't execute, 
# the mere presence of the assignment statement 
# causes z to come to life. 
irb(main):002:0> z = 123 if false 
=> nil 
irb(main):003:0> defined?(z) 
=> "local-variable" 
irb(main):004:0> z 
=> nil 

Jetzt können wir Ihr erstes Beispiel herauszufinden.

foo = true unless defined?(foo) 

Ist foo definiert? Bevor wir ENTER in irb drücken, nein. Das Vorhandensein der Zuweisungsanweisung führt jedoch dazu, dass foo zum Leben erweckt wird. Das heißt, die Zuweisungsanweisung wird nicht ausgeführt, wobei foo existiert, aber nil als Wert hat. Und was ist der letzte Ausdruck in der irb Linie ausgewertet? Es ist unless defined?(foo), die nil auswertet.

Weitere Informationen darüber, wie Zuordnungen (auch solche, die nicht ausgeführt werden) dazu führen, dass Variablen vorhanden sind, finden Sie in dieser Beschreibung von Variable/Method Ambiguity.

In Ihrem zweiten Beispiel gibt es nichts Geheimnisvolles: fooo ist nicht definiert, also wird der Code im Block ausgeführt und fooo auf false gesetzt. Diese Zuweisung ist der letzte ausgewertete Ausdruck, also ist false der Rückgabewert unseres Blocks.

1

August alle sehen gut in 1.8.7:

$ irb 
irb(main):001:0> unless defined?(fooo); fooo = true; end 
=> true 
irb(main):002:0> fooo 
=> true 
irb(main):003:0> `ruby --version` 
=> "ruby 1.8.7 (2008-06-20 patchlevel 22) [i486-linux]\n" 
Verwandte Themen