Почему собственный класс не эквивалентен самому себе.класс, когда это выглядит так похожи?
я где-то пропустил записку, и я надеюсь, что вы объясните мне это.
почему собственный класс объекта отличается от self.class?
class Foo
def initialize(symbol)
eigenclass = class << self
self
end
eigenclass.class_eval do
attr_accessor symbol
end
end
end
мой поезд логики, который приравнивает собственный класс с class.self довольно проста:
class << self - это способ объявления методов класса, а не методов экземпляра. Это короткий путь к def Foo.bar.
Итак, в пределах ссылки на объект класса, возвращая self должны быть идентичны self.class. Это потому что class << self установить self до Foo.class для определения методов/атрибутов класса.
я просто запуталась? Или это хитрый трюк метапрограммирования Ruby?
3 ответа:
class << self- это больше, чем просто способ объявить методы класса (хотя он может быть использован таким образом). Вероятно, вы видели некоторые использования, как:class Foo class << self def a print "I could also have been defined as def Foo.a." end end endэто работает, и эквивалентно
def Foo.a, но это немного тонкий. Секрет в том, чтоselfв этом контексте, относится к объектуFoo, чей класс является уникальным, анонимным подклассомClass. Этот подкласс называетсяFoo' s eigenclass. Так чтоdef aсоздает новый методainFooсобственный класс, доступный с помощью обычного синтаксиса вызова метода:Foo.a.теперь давайте рассмотрим другой пример:
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этот пример такой же, как и предыдущий, хотя сначала может быть трудно сказать.
frobопределяется, а не наStringкласс, но на собственном классеstrуникальный анонимный подклассString. Так чтоstrестьfrobметод, но экземплярыStringвообще не. Мы могли бы также иметь переопределенные методы String (очень полезно в некоторых сложных сценариях тестирования).теперь мы готовы понять ваш оригинальный пример. Внутри
Foo'ы initialize метод,selfотносится не к классуFoo, но к какому-то экземпляр наFoo. Его собственный класс является подклассомFoo, но неFoo; это не могло быть, иначе трюк, который мы видели во втором примере, не мог работать. Так что продолжайте свой пример: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.надеюсь, что это помогает.
самый простой ответ:собственный класс не может быть создан.
class F def eigen class << self self end end end F.new.eigen.new #=> TypeError: can't create instance of virtual class
Иегуда Кац довольно хорошо объясняет тонкости в "метапрограммирование в Ruby: это все о себе"