class << self
ist mehr als nur eine Möglichkeit, Klassenmethoden zu deklarieren (obwohl es auf diese Weise verwendet werden kann). Wahrscheinlich haben Sie eine Verwendung gesehen wie:
class Foo
class << self
def a
print "I could also have been defined as def Foo.a."
end
end
end
Dies funktioniert und ist gleichbedeutend mit def Foo.a
, aber die Art und Weise, wie es funktioniert, ist ein wenig subtil. Das Geheimnis ist, dass es self
sich in diesem Zusammenhang auf das Objekt bezieht Foo
, dessen Klasse eine eindeutige, anonyme Unterklasse von ist Class
. Diese Unterklasse heißt Foo
‚s Eigenklasse . Erstellt also def a
eine neue Methode, die a
in Foo
der Eigenklasse aufgerufen wird und auf die über die normale Methodenaufrufsyntax zugegriffen werden kann : Foo.a
.
Schauen wir uns nun ein anderes Beispiel an:
str = "abc"
other_str = "def"
class << str
def frob
return self + "d"
end
end
print str.frob # => "abcd"
print other_str.frob # => raises an exception, 'frob' is not defined on other_str
Dieses Beispiel ist das gleiche wie das letzte, obwohl es zunächst schwer zu sagen sein kann. frob
wird nicht für die String
Klasse, sondern für die Eigenklasse von str
einer eindeutigen anonymen Unterklasse von definiert String
. So str
hat eine frob
Methode, aber Instanzen von String
im Allgemeinen nicht. Wir könnten auch Methoden von String überschrieben haben (sehr nützlich in bestimmten kniffligen Testszenarien).
Jetzt können wir Ihr ursprüngliches Beispiel verstehen. Foo
Die Initialisierungsmethode von Inside self
bezieht sich nicht auf die Klasse Foo
, sondern auf eine bestimmte Instanz von Foo
. Seine Eigenklasse ist eine Unterklasse von Foo
, aber es ist nicht Foo
; es könnte nicht sein, sonst könnte der Trick, den wir im zweiten Beispiel gesehen haben, nicht funktionieren. Um Ihr Beispiel fortzusetzen:
f1 = Foo.new(:weasels)
f2 = Foo.new(:monkeys)
f1.weasels = 4 # Fine
f2.monkeys = 5 # Also ok
print(f1.monkeys) # Doesn't work, f1 doesn't have a 'monkeys' method.
Hoffe das hilft.