Почему собственный класс не эквивалентен самому себе.класс, когда это выглядит так похожи?
я где-то пропустил записку, и я надеюсь, что вы объясните мне это.
почему собственный класс объекта отличается от 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
создает новый методa
inFoo
собственный класс, доступный с помощью обычного синтаксиса вызова метода: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: это все о себе"