• Serif
  • Sans

Ruby中的元编程

方法的调用

当你在调用某一个方法的时候,Ruby会完成下面的步骤:

  • 找到这个方法,我们把这个过程称作方法查找(method lookup);
  • 执行这个方法,为了执行这个方法,Ruby需要一个叫做self的伪变量;

方法的查找

要理解Ruby的方法查找,你需要了解下面两个概念:接受者(receiver)祖先链(ancestors chain)。接受者就是方法的调用者。例如,对调用an_object.display()来说,an_object就是接受者。而关于祖先链,请考察任何一个Ruby类的内部。想象一下从一个类移动到其父类,然后再移动到父类的父类,直到到达Object类(默认的父类),然后继续移动,最终到达BasicObject类(Ruby层级模型中的根)。你遍历这些类所走过的路径就是"祖先链"(祖先链中也包括模块)。

因此,为了查找方法,Ruby首先进入receiver所属的类,并以此为起始,沿着祖先链不断前进,直到找到目标方法。这种行为也被称作"向右一步,再向上(one step to the right, then up)"规则:向右一步,进入reciver所属的类,然后再向上查找祖先链,直到找到目标方法。(译者注:如果遍历完祖先链也没有找到方法的话,会调用method_missing方法,如果这个方法没有被定义,则抛出NoMethodError)当你在一个类中包含一个模块时,Ruby创建了一个匿名类来封装这个模块,并将这个匿名类插入到祖先链中,也在这个类的上方。

下面的代码演示了一次方法查找:

class A
 def foo
 end
end
class B < A
 def bar
 # bar method in B
 end
end
class C < B
 def bar
 # bar method in C
 # overwriting superclass' method
 end
end
obj = C.new
obj.bar #=> in C class
obj.foo #=> not in C class
 #=> then go to C's superclass B
 #=> not in B class
 #=> then go to B's superclass A
 #=> execute it

self

  • 在Ruby中,self是一个很特殊的变量,它总是指向当前对象(current object);
  • self被认为是默认的receiver。也就是说,你如果没有明确指出receiver,那么系统将把self当做receiver;
  • 实例变量是在self(当前对象)中查找的。也就是说,如果我使用@var,那么Ruby就会在self所指向的对象中去寻找此实例变量。需要注意的是,实例变量并不是由类定义的,它们也和子类以及继承机制无关。

因此,当我们在调用一个明确指出receiver的方法时,Ruby会按照下面的步骤执行:

obj.do_method(param)
  • self指向obj;
  • self所属的类中查找do_method(param)方法(方法是存放在类中,而不是实例中!);
  • 调用方法do_method(param);

AltStyle によって変換されたページ (->オリジナル) /