Frage Warum entspricht die Eigenklasse nicht der self.class, wenn sie so ähnlich aussieht?


Ich habe das Memo irgendwo vergessen, und ich hoffe, du erklärst mir das.

Warum unterscheidet sich die Eigenklasse eines Objekts? self.class?

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

Mein Zug der Logik, der die Eigenklasse gleichstellt class.self ist ziemlich einfach:

class << self ist eine Möglichkeit, Klassenmethoden anstelle von Instanzmethoden zu deklarieren. Es ist eine Abkürzung zu def Foo.bar.

Also innerhalb der Referenz auf das Klassenobjekt, zurückgeben self sollte identisch sein mit self.class. Das ist weil class << self würde setzen self zu Foo.class zur Definition von Klassenmethoden / Attributen.

Bin ich nur verwirrt? Oder ist das ein hinterhältiger Trick der Ruby Metaprogrammierung?


76
2017-10-27 13:31


Ursprung


Antworten:


class << self ist mehr als nur eine Möglichkeit, Klassenmethoden zu deklarieren (obwohl es auf diese Weise verwendet werden kann). Wahrscheinlich haben Sie eine Anwendung wie:

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

Das funktioniert und entspricht def Foo.a, aber die Art, wie es funktioniert, ist ein wenig subtil. Das Geheimnis ist das selfbezieht sich in diesem Zusammenhang auf das Objekt Foo, deren Klasse eine eindeutige, anonyme Unterklasse von ist Class. Diese Unterklasse wird aufgerufen Fooist es Eigenklasse. Damit def a erstellt eine neue Methode namens a im Foo's Eigenklasse, erreichbar über die normale Methodenaufrufsyntax: Foo.a.

Sehen 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 am Anfang vielleicht schwer zu sagen ist. frob ist definiert, nicht auf der String Klasse, aber auf der Eigenklasse von str, eine einzigartige anonyme Unterklasse von String. Damit str hat ein frob Methode, aber Instanzen von String im Allgemeinen nicht. Wir könnten auch Methoden von String überschrieben haben (sehr nützlich in bestimmten schwierigen Testszenarien).

Jetzt sind wir in der Lage, Ihr ursprüngliches Beispiel zu verstehen. Innerhalb FooInitialisierungsmethode, self bezieht sich nicht auf die Klasse Foo, aber zu etwas Besonderem Beispiel 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 sahen, nicht funktionieren. Also, 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.


114
2017-10-27 13:59



Die einfachste Antwort: Die Eigenklasse kann nicht instanziiert werden.

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

44
2017-11-16 16:09



Yehuda Katz ist ziemlich gut darin, die Feinheiten in "Metaprogrammierung in Ruby: Es geht um das Selbst"


11
2017-12-21 01:38