Метапрограммирование. Где происходит диспетчеризация метода, когда мы вызываем метод экземпляра, определенный в методе класса?
Я читаю метапрограммирование Ruby и просто хочу кое-что прояснить в следующем перефразированном коде:
class MyClazz
def self.my_class_method(name)
define_method(name) {
# do stuff
}
end
my_class_method :foo
my_class_method :bar
end
# The code above generates instance methods:
# def foo
# do stuff
# end
# def bar
# do stuff
# end
Q1 Мой первый вопрос касается двух вызовов методов в конце файла: my_class_method :foo
а также my_class_method :bar
, Правильно ли я считаю, что они оба вызываются автоматически при создании экземпляра объекта MyClazz?
Q2 Когда Ruby генерирует эти методы (def foo
а также def bar
), он поместит их в собственный класс MyClazz, даже если они являются методами экземпляра. Значит ли это, что Ruby при необходимости ищет собственный класс для методов класса и экземпляра?
Я просто хочу прояснить это, прежде чем углубиться в книгу.
2 ответа
Ответ 1: (короткий) Они вызываются, когда создается экземпляр ruby. MyClass
экземпляр (типа Class
).
(длинный) Когда интерпретатор Ruby видит определение класса (class MyClazz
) он создает экземпляр этого класса и оценивает весь код внутри определения класса.
В твоем случае MyClazz
константа, которая содержит ссылку на объект класса Class
, И когда Ruby его инициализирует, он выполняет код внутри определения класса - определяет метод singleton my_class_method
этого Class
экземпляр и выполняет метод my_class_method
дважды в контексте этого Class
пример.
Ответ 2: (короткий) Module#define_method
закрытый метод добавляет метод в таблицу методов Class
экземпляр (таблица методов содержит методы экземпляра класса). Это не влияет на собственный класс объекта istance / объекта класса.
(long) Когда вы вызываете метод экземпляра для объекта, Ruby сначала ищет этот метод в собственном классе этого объекта, затем в суперклассе собственного класса (это будет Class
объект класса объекта). Но это не будет выглядеть в собственном классе MyClazz
объект.
Пример:
obj = MyClazz.new
obj.foo # => ok
obj.foo
буду искать foo
определение метода в собственном классе obj
объект, то будет искать методы экземпляра MyClass
(экземпляр класса Class
), то в суперклассе MyClass
объект (в вашем случае это Object
класс) и т. д.
obj = MyClass.new
MyClass.my_class_method :baz
obj.baz # => ok
MyClass.my_class_method
буду искать my_class_method
определение метода в собственном классе MyClass
объект (sidenote: собственный класс класса иногда называют метаклассом), и он найдет его здесь и добавит baz
метод экземпляра для класса MyClass
,
A1: Да, эти методы создаются при создании экземпляра.
A2: Расс Олсен отлично объясняет это в своей книге Eloquent Ruby. Собственный класс (или одноэлементный класс) "находится между каждым объектом и его обычным классом". Таким образом, когда Ruby не находит метод, который ищет в методах экземпляра, он начинает перемещаться по дереву наследования. Следующая остановка - собственный класс, а оттуда - сам класс.
Олсен также дает интересную дискуссию о том, что все методы класса на самом деле являются одноэлементными методами между новым классом и объектом класса.