Pourquoi la classe propre n'est-elle pas équivalente à self.class, alors qu'elle a l'air si semblable?

StackOverflow https://stackoverflow.com/questions/1630815

Question

J'ai oublié le mémo quelque part et j'espère que vous me l'expliquerez.

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 la classe propre à class.self est plutôt simple:

class << self est un moyen de déclarer des méthodes de classe plutôt que des méthodes d'instance. C'est un raccourci vers def Foo.bar.

Ainsi, dans la référence à l'objet de classe, le renvoi self doit être identique à Foo.class. En effet, <=> définirait <=> sur <=> pour la définition des méthodes / attributs de classe.

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

Était-ce utile?

La solution

class << self est plus qu'un simple moyen de déclarer des méthodes de classe (bien qu'il puisse être utilisé de cette façon). Vous avez probablement déjà vu des utilisations telles que:

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 unique et anonyme de Class. Cette sous-classe est appelée def a eigenclass . Ainsi, a crée une nouvelle méthode appelée Foo.a dans la classe propre de frob, accessible par la syntaxe d'appel de méthode habituelle: String.

Maintenant, regardons un exemple différent:

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 le savoir au début. str est défini, pas sur la classe <=>, mais sur la classe propre de <=>, une sous-classe anonyme unique de <=>. Donc <=> a une méthode <=>, mais pas les instances de <=> en général. Nous pourrions également avoir remplacé les méthodes de String (très utile dans certains scénarios de test difficiles).

Nous sommes maintenant en mesure de comprendre votre exemple initial. Dans la méthode d'initialisation de <=>, <=> ne fait pas référence à la classe <=>, mais à une instance particulière de <=>. Sa classe propre est une sous-classe de <=>, mais ce n'est pas <=>; cela ne pouvait pas être, sinon le truc que nous avons vu dans le deuxième exemple ne pourrait pas marcher. 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.

J'espère que cela vous aidera.

Autres conseils

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

Yehuda Katz explique très bien les subtilités de & "; Métaprogrammation en Ruby: tout est une question de soi &";

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top