class << selfist 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 selfsich 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 aeine neue Methode, die ain Fooder 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. frobwird nicht für die StringKlasse, sondern für die Eigenklasse von streiner eindeutigen anonymen Unterklasse von definiert String. So strhat eine frobMethode, aber Instanzen von Stringim 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. FooDie Initialisierungsmethode von Inside selfbezieht 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.