2009-10-27 9 views
74

J'ai manqué le mémo quelque part, et j'espère que vous m'expliquerez cela.Pourquoi la classe propre n'est-elle pas équivalente à self.class, quand elle a l'air si similaire?

Pourquoi la classe propre d'un objet est-elle différente de self.class?

class Foo 
    def initialize(symbol) 
    eigenclass = class << self 
     self 
    end 
    eigenclass.class_eval do 
     attr_accessor symbol 
    end 
    end 
end 

Mon train de logique qui assimile les eigenclass avec class.self est assez simple:

class << self est une façon de déclarer les méthodes de classe, plutôt que des méthodes d'instance. C'est un raccourci vers def Foo.bar. Par conséquent, dans la référence à l'objet de classe, self doit être identique à self.class. En effet, class << self définirait self à Foo.class pour la définition des méthodes/attributs de classe.

Suis-je simplement confus? Ou est-ce un truc sournois de méta-programmation Ruby?

Répondre

106

class << self est plus qu'un moyen de déclarer des méthodes de classe (bien qu'il puisse être utilisé de cette façon). Probablement que vous avez vu une utilisation comme:

class Foo 
    class << self 
    def a 
     print "I could also have been defined as def Foo.a." 
    end 
    end 
end 

Cela fonctionne, et équivaut à def Foo.a, mais la façon dont cela fonctionne est un peu subtile. Le secret est que self, dans ce contexte, fait référence à l'objet Foo, dont la classe est une sous-classe anonyme unique de Class. Cette sous-classe est appelée Fooclasse propre. Donc def a crée une nouvelle méthode appelée a dans la classe propre Foo, accessible par la syntaxe d'appel de méthode normale: Foo.a.

Maintenant, regardons un autre exemple:

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 

Cet exemple est le même que le dernier, mais il peut être difficile de dire au début. frob est défini, pas sur la classe String, mais sur la classe propre de str, une sous-classe anonyme unique de String. Donc str a une méthode frob, mais les instances de String en général ne le font pas. Nous pourrions aussi avoir des méthodes surchargées de String (très utile dans certains scénarios de test difficiles).

Maintenant nous sommes équipés pour comprendre votre exemple original. À l'intérieur Foo méthode d'initialisation, self se réfère pas à la classe Foo, mais à certains en particulier de Foo. Sa classe propre est une sous-classe de Foo, mais elle n'est pas Foo; ça ne pouvait pas l'être, sinon le truc que nous avons vu dans le second exemple ne pouvait pas fonctionner. Donc, pour continuer votre exemple:

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. 

Espérons que cela aide.

+0

Ainsi donc, chaque instance est une sous-classe anonyme de la classe créée? –

+19

* class * de chaque instance est une sous-classe anonyme de la classe créée. La classe f1 est une sous-classe anonyme de Foo, la classe de Foo est une sous-classe anonyme de Class. –

+4

belle réponse :) beaucoup de gens ne comprennent pas cela aussi clairement que vous le faites. – horseyguy

43

La réponse la plus simple: la classe propre ne peut pas être instanciée.

class F 
def eigen 
    class << self 
    self 
    end 
end 
end 
F.new.eigen.new #=> TypeError: can't create instance of virtual class 
+0

vous pouvez avoir seulement 1 point sur ce site, mais je vous aime et votre style. – horseyguy

+0

D'accord avec rampe; c'est une bonne réponse –

+1

Des informations intéressantes, mais ne répondez pas à la question – Alexey