我正在阅读元编程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在需要时同时考虑类和实例方法的本征类?
我只是想在深入到书中之前澄清一下。
答案1:
(短)当ruby实例化MyClass
实例(类型为Class
)时调用它们。
(long)当Ruby解释器看到一个类定义(class MyClazz
)时,它会实例化这个类的一个实例,并评估类定义中的所有代码。
在您的例子中,MyClazz
是一个常量,它保持对类Class
的对象的引用。当Ruby初始化它时,它在类定义中执行代码——定义这个Class
实例的singleton方法my_class_method
,并在这个Class
实例的上下文中执行两次方法my_class_method
。
答案2:
(短)Module#define_method
私有方法将方法添加到Class
实例的方法表中(方法表保存类的实例方法)。它不影响距离对象/类对象的本征类。
(long)当您在对象上调用实例方法时,Ruby首先在该对象的本征类中查找该方法,然后在本征类的超类中查找(它将是该对象类的Class
对象)。但它不会出现在MyClazz
的本征类中对象
示例:
obj = MyClazz.new
obj.foo # => ok
obj.foo
将在obj
对象的本征类中查找foo
方法定义,然后查找MyClass
的实例方法(类Class
的实例),然后在MyClass
对象的超类中(在您的情况下,这是Object
类)等
obj = MyClass.new
MyClass.my_class_method :baz
obj.baz # => ok
MyClass.my_class_method
将在MyClass
对象的本征类中寻找my_class_method
方法定义称为元类),它将在这里找到它,并将baz
实例方法添加到类MyClass
中。
A1:是的,这些方法是在实例化时创建的。
A2:Russ Olsen在他的书《Eloquent Ruby》中对此做了很好的解释。本征类(或单例类)"位于每个对象及其正则类之间"。因此,当Ruby在实例方法中找不到它要查找的方法时,它将开始向上遍历继承树。下一站是本征类,然后是类本身。
Olsen还对所有Class方法实际上是新类和Class对象之间的单例方法进行了有趣的讨论。