2010-10-26 3 views
12

Samt in Ruby 1.8.7 und 1.9.2:In Ruby, warum nach dem Start irb, foo.nil? sagt undefined Fehler und @ foo.nil? gibt "wahr", und @@ wah.nil? gibt wieder Fehler?

$ irb 

ruby-1.8.7-p302 > foo.nil? 
NameError: undefined local variable or method `foo' for #<Object:0x3794c> 
    from (irb):1 

ruby-1.8.7-p302 > @bar.nil? 
=> true 

ruby-1.8.7-p302 > @@wah.nil? 
NameError: uninitialized class variable @@wah in Object 
    from (irb):3 

warum die Instanzvariable anders behandelt als ein lokales und Klassenvariable?

Antwort

17

In Ruby werden die meisten nicht initialisierten oder sogar nicht existierenden Variablen auf ausgewertet. Dies gilt sowohl für lokale Variablen, Instanzvariablen und globale Variablen:

defined? foo  #=> nil 
local_variables #=> [] 
if false 
    foo = 42 
end 
defined? foo  #=> 'local-variable' 
local_variables #=> [:foo] 
foo    #=> nil 
foo.nil?   #=> true 

defined? @bar  #=> nil 
instance_variables #=> [] 
@bar    #=> nil 
@bar.nil?   #=> true 
# warning: instance variable @bar not initialized 

defined? $baz  #=> nil 
$baz    #=> nil 
# warning: global variable `$baz' not initialized 
$baz.nil?   #=> true 
# warning: global variable `$baz' not initialized 

Es ist aber nicht wahr, für Klassenhierarchie Variablen und Konstanten:

defined? @@wah  #=> nil 
@@wah 
# NameError: uninitialized class variable @@wah in Object 

defined? QUUX  #=> nil 
QUUX 
# NameError: uninitialized constant Object::QUUX 

Dies ist ein roter Hering:

defined? fnord  #=> nil 
local_variables #=> [] 
fnord 
# NameError: undefined local variable or method `fnord' for main:Object 

Der Grund, warum Sie hier einen Fehler erhalten, ist nicht dass unitialized lokale Variablen nicht nil auswerten, es ist t Hut fnord ist mehrdeutig: es könnte sein entweder eine argumentlose Nachricht an den Standardempfänger (d. h. äquivalent zu self.fnord()) oder ein Zugriff auf die lokale Variable fnord.

Damit eindeutig zu machen, benötigen Sie einen Empfänger oder eine Argumentliste (auch wenn sie leer) hinzufügen Ruby zu sagen, dass es eine Nachricht zu senden ist:

self.fnord 
# NoMethodError: undefined method `fnord' for main:Object 
fnord() 
# NoMethodError: undefined method `fnord' for main:Object 

oder sicherstellen, dass die Parser (nicht die Auswerter) parst ( nicht ausführt) eine Zuordnung vor der Verwendung, Rubin zu sagen, dass es sich um eine lokale Variable ist:

if false 
    fnord = 42 
end 
fnord    #=> nil 

Warum die Instanzvariable anders behandelt als eine lokale Variable und eine Klassenvariable?

Es ist nicht, eigentlich. Es wird genauso behandelt wie eine lokale Variable. Die Klassenhierarchievariable verhält sich unterschiedlich, lokale Variablen, Instanzvariablen und globale Variablen verhalten sich alle gleich.

gibt es andere Gründe & hellip; Können sich Klassenvariablen nicht so verhalten?

Ich weiß es nicht. Zum Beispiel ist es sehr praktisch, da im Gegensatz zu Java, wo beispielsweise Instanzvariablen in der Klassendefinition deklariert werden und somit immer für jede Instanz der Klasse existieren, in Ruby Instanzvariablen nirgends deklariert werden. Sie entstehen einfach magisch, sobald sie zugewiesen sind. Da Instanzvariablen nicht notwendigerweise garantiert existieren, wäre das Schreiben von Methoden, die Instanzvariablen verwenden, ein Schmerz, wenn sie Ausnahmen auslösen.

Warum Klassenhierarchievariablen sind anders, ich habe keine Ahnung. Vielleicht liegt es daran, dass sie von niemandem verwendet werden oder weil sie im Allgemeinen dazu neigen, im Klassenkörper initialisiert zu werden und einfach nicht aufgerufen werden, wenn sie nicht initialisiert werden.

Verwandte Themen