ich hatte vergessen, es war ein "Klasseninstanzvariable" -Konzept in Ruby. Auf jeden Fall schien das Problem des OP rätselhaft zu sein und wurde in keiner der Antworten bis jetzt behandelt, abgesehen von einem Hinweis in kchs Antwort: Es ist ein Problem des Umfangs. (Hinzugefügt am Edit: Eigentlich sris Antwort tut adressieren diesen Punkt am Ende, aber ich werde diese Antwort trotzdem stehen lassen, da ich denke, dass der Beispielcode zum Verständnis des Problems nützlich sein könnte.)
In einem Ruby-Klasse, ein Variablenname beginnend mit @
kann sich auf eine zwei Variablen beziehen: entweder auf eine Instanzvariable oder auf eine Klasseninstanzvariable, je nachdem, wo in der Klasse, auf die sie bezogen ist. Das ist ein ziemlich subtiler Fehler.
Ein Beispiel wird den Punkt verdeutlichen. Hier ist eine kleine Ruby-Test-Klasse (alle Code in irb getestet):
class T
@@class_variable = "BBQ"
@class_instance_variable_1 = "WTF"
@class_instance_variable_2 = "LOL"
def self.class_method
puts "@@class_variable == #{@@class_variable || 'nil'}"
puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
puts "@instance_variable == #{@instance_variable || 'nil'}"
end
def initialize
@instance_variable = "omg"
# The following line does not assign a value to the class instance variable,
# but actually declares an instance variable withthe same name!
@class_instance_variable_1 = "wtf"
puts "@@class_variable == #{@@class_variable || 'nil'}"
# The following two lines do not refer to the class instance variables,
# but to the instance variables with the same names.
puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
puts "@instance_variable == #{@instance_variable || 'nil'}"
end
def instance_method
puts "@@class_variable == #{@@class_variable || 'nil'}"
# The following two lines do not refer to the class instance variables,
# but to the instance variables with the same names.
puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}"
puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}"
puts "@instance_variable == #{@instance_variable || 'nil'}"
end
end
Ich nannte die Variablen nach dem, was ich dachte, sie waren, aber das erweist sich nicht immer der Fall zu sein:
irb> T.class_method
@@class_variable == BBQ
@class_instance_variable_1 == WTF # the value of the class instance variable
@class_instance_variable_2 == LOL # the value of the class instance variable
@instance_variable == nil # does not exist in the class scope
=> nil
irb> t = T.new
@@class_variable == BBQ
@class_instance_variable_1 == wtf # the value of the instance variable
@class_instance_variable_2 == nil # the value of the instance variable
@instance_variable == omg
=> #<T:0x000000015059f0 @instance_variable="omg", @class_instance_variable_1="wtf">
irb> t.instance_method
@@class_variable == BBQ
@class_instance_variable_1 == wtf # the value of the instance variable
@class_instance_variable_2 == nil # the value of the instance variable
@instance_variable == omg
=> nil
irb> T.class_method
@@class_variable == BBQ
@class_instance_variable_1 == WTF # the value of the class instance variable
@class_instance_variable_2 == LOL # the value of the class instance variable
@instance_variable == nil # does not exist in the class scope
=> nil
Die @@class_variable
und @instance_variable
verhalten sich immer wie erwartet: ersteres ist auf der Klassenebene definiert, und ob es in einer Klassenmethode oder einer Instanzmethode referenziert wird, es enthält Wert, der ihm oben zugeordnet ist. Letzterer erhält nur einen Wert in einem Objekt der Klasse T
. In einer Klassenmethode verweist er auf eine unbekannte Variable, deren Wert nil
ist.
Die Klassenmethode imaginativ mit dem Namen class_method
gibt die Werte @@class_variable
und die beiden @class_instance_variable
s wie erwartet aus, dh wie oben in der Klasse initialisiert. Jedoch in den Instanzmethoden initialize
und instance_method
, verschiedenen Variablendes gleichen Namens zugegriffen wird, das heißt, Instanzvariablen, nicht die Klasseninstanzvariablen.
können Sie sehen, dass die Zuordnung in der initialize
Methode nicht die Klasseninstanzvariable @class_instance_variable_1
, weil der spätere Aufruf von class_method
gibt seinen alten Wert nicht beeinträchtigte, "WTF"
. Stattdessen hat Methode initialize
eine neue Instanzvariable deklariert, eine, die ist auch benannt (irreführend) @class_instance_variable_1
. Der Wert zugewiesen, "wtf"
, ausgegeben durch Verfahren initialize
und instance_method
.
Die Variable @class_instance_variable_2
im Beispiel Code variabler @hello
in das ursprüngliche Problem äquivalent: es als Klasseninstanzvariable initialisiert erklärt und wird, aber, wenn eine Instanz-Methode auf eine Variable dieses Namens bezieht, sieht es tatsächlich eine Instanz Variable mit dem gleichen Namen - eine, die nie erklärt wurde, so ist ihr Wert Null.
Du sagst "sie kommen zum ersten Mal ins Leben, wenn sie ihnen zugewiesen werden", aber das OP zeigte ein Beispiel mit (scheinbarer) Zuweisung früher als in deinem Beispiel, und das Problem ist, dass diese Variable nicht zum Leben geführt hat. – kaleidic
@ kaleidic Genau. Ich bin ein wenig verwirrt über die Anzahl der Upvotes zu dieser Antwort, die nicht auf die Frage des OP eingehen. Tatsächlich tritt die Klasseninstanzvariable '@ hello' * * in Zeile 2 des Beispielcodes auf, aber das Problem ist, dass dies nicht die Variable ist, auf die sich Zeile 4 bezieht. Siehe meine Antwort unten für weitere Details. –
Entschuldigung, Sie beantworten am Ende tatsächlich die Frage, die ich bei der ersten Lesung übersehen habe. –