今天有点蛋疼的想验证一把 ruby 寻找方法的搜索路径, 例
module M; end
class B; end
class C <B; include M; end
c = C.new
那么 c.send(:to_s) 搜索路径应该是怎么样的呢?
我认为完整的路径为:
c -> c.engienclass -> C -> M -> B ->Object->Kernel
本想 debug 一把,不知道为何下了断点进不去。翻了下代码看了看,觉得怎么略过了 engienclass 和 module,求解?
search_method(VALUE klass, ID id)
{
st_data_t body;
if (!klass) {
return 0;
}
while (!st_lookup(RCLASS_M_TBL(klass), id, &body)) {
klass = RCLASS_SUPER(klass);
if (!klass) {
return 0;
}
}
return (rb_method_entry_t *)body;
}
@hhui 并没有跳过 engienclass 和 module. 简单来说就是,Ruby 在 include 和 define method 的时候,已经对 klass 做了处理,已经串起来了。具体你可以看看这两个函数:
vm_define_method
rb_include_module
@hhuai 略说一下就是: 1 .如果你对 c 定义了一个单例方法,如:
def c.x
'ooO'
end
这时,c 对象的 klass 已经不是类 C,而是成了 c.engienclass。并且 c.engienclass 的 super 则指向类 C。
2.对于 C include M: Ruby 会为模块 M 建立一个代理类,(姑且名为 M-proxy). 这时,C 的 super 就不是 B 了,而是 M-proxy,M-proxy 的 super 则是 B。注意,这个 M-proxy 类的实例变量表和方法表都指向了模块 M 的实例变量表和方法表 。所以,在方法搜索时,依然也会查找 M 的方法表。
这样,这个链条就串起来了。所以说,并没有跳过 engienclass 和 module.
s.class.ancestors .join(" ~> ")
=> "C -> M -> B -> Object -> Kernel -> BasicObject"
#8 楼 @clc3123 有 Ruby Hacking Guide http://thinkinginruby.group.iteye.com/group/wiki/1262-chinese-version-of-the-ruby-hacking-guide 不过已经很老了,也没翻译完。如果日文好~ 你就直接肯日文。:) 是以 Ruby1.7.3 为 base,老~,十分的老。
个人如果感兴趣,就下载 ruby1.9 的源码~,自己看源码。这应该是最好的途径。
还是重申:就学习 Ruby 语言来说,则完全可以忽略 C 语言层面的东西 :>