元编程:当我们调用在类方法中定义的实例方法时,方法调度的位置在哪里?

时间:2012-03-24 04:47:28

标签: ruby metaprogramming eigenclass

我正在阅读Metaprogramming 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 :foomy_class_method :bar。我是否认为在实例化MyClazz对象时会自动调用它们?

Q2 当Ruby生成这些方法(def foodef bar)时,它会将它们放在 MyClazz的本征类中,即使它们是实例方法。那么这是否意味着Ruby在需要时会查找类和实例方法的本征类?

我只是想在我向书中移动太远之前将其清除。

2 个答案:

答案 0 :(得分:3)

答案1: (简短)当ruby实例化MyClass实例(类型为Class)时,会调用它们。

(long)当Ruby解释器看到类定义(class MyClazz)时,它实例化该类的实例并评估类定义中的所有代码。

在您的情况下,MyClazz是一个常量,它包含对类Class的对象的引用。当Ruby初始化它时,它在类定义中执行代码 - 定义此my_class_method实例的单例方法Class,并在此my_class_method实例的上下文中执行两次方法Class

答案2: (短) Module#define_method私有方法将方法添加到Class实例的方法表中(方法表保存实例方法)班级)。它不影响istance对象/类对象的本征类。

(long)当你在对象上调用实例方法时,Ruby首先在这个对象的本征类中查找此方法,然后在eigenclass的超类中查找(它将是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方法定义(旁注:类的本征类有时是  称为元类),它将在此处找到它,并将baz实例方法添加到类MyClass

答案 1 :(得分:2)

A1:是的,这些方法是在实例化时创建的。

A2:Russ Olsen在他的“Eloquent Ruby”一书中做了很好的解释。特征类(或单例类)“位于每个对象及其常规类之间”。因此,当Ruby没有找到它在实例方法中寻找的方法时,它将开始沿着继承树向上移动。下一站是本征类,然后是类本身。

Olsen还提供了一个有趣的讨论,关于所有Class方法实际上是新类和Class对象之间的单例方法。