class << self
jest czymś więcej niż tylko sposobem deklarowania metod klasowych (chociaż można tego używać w ten sposób). Prawdopodobnie widziałeś takie użycie, jak:
class Foo
class << self
def a
print "I could also have been defined as def Foo.a."
end
end
end
To działa i jest równoważne def Foo.a
, ale sposób, w jaki to działa, jest nieco subtelny. Sekret polega na tym self
, że w tym kontekście odnosi się do obiektu Foo
, którego klasa jest unikalną, anonimową podklasą klasy Class
. Podklasa ta nazywana jest Foo
„s eigenclass . Tak def a
tworzy nową metodę zwaną a
w Foo
„s eigenclass, dostępną przez normalną składnią Sposób połączenia: Foo.a
.
Spójrzmy teraz na inny przykład:
str = "abc"
other_str = "def"
class << str
def frob
return self + "d"
end
end
print str.frob
print other_str.frob
Ten przykład jest taki sam jak poprzedni, chociaż na początku może być trudno powiedzieć. frob
jest zdefiniowana nie w String
klasie, ale w klasie własnej str
, unikalnej anonimowej podklasie String
. str
Ma więc frob
metodę, ale instancje String
generalnie nie. Mogliśmy również przesłonić metody String (bardzo przydatne w niektórych trudnych scenariuszach testowania).
Teraz jesteśmy przygotowani, aby zrozumieć Twój oryginalny przykład. Wewnątrz Foo
inicjuj metoda jest, self
nie odnosi się do grupy Foo
, ale w pewnym konkretnym przypadku z Foo
. Jego klasa własna jest podklasą Foo
, ale tak nie jest Foo
; to niemożliwe, bo inaczej sztuczka, którą widzieliśmy w drugim przykładzie, nie zadziałała. Kontynuując przykład:
f1 = Foo.new(:weasels)
f2 = Foo.new(:monkeys)
f1.weasels = 4
f2.monkeys = 5
print(f1.monkeys)
Mam nadzieję że to pomoże.
Najprostsza odpowiedź: nie można utworzyć instancji klasy własnej.
class F def eigen class << self self end end end F.new.eigen.new #=> TypeError: can't create instance of virtual class
źródło
Yehuda Katz całkiem nieźle radzi sobie z wyjaśnianiem subtelności w „ Metaprogramowanie w języku Ruby: to wszystko o jaźni ”
źródło