Ruby Koan中父类调用子类方法的原理疑问
问题解答:Ruby父类方法为何能调用子类定义的方法?
你这个疑问其实是对Ruby面向对象中方法调用的接收者和方法查找链理解上的小偏差,我来给你拆解清楚:
核心原因:方法调用基于实例的实际类型,而非方法定义的类
当你运行AboutAsserts相关的代码时,实际创建的是AboutAsserts类的实例,而不是父类Koan的实例。虽然meditate方法定义在Koan里,但这个方法是在子类实例上执行的——此时方法内部的self指向的是这个子类实例,而不是父类的对象。
具体拆解:
- Ruby的方法查找规则:当调用
send(name)时,Ruby会从self(当前子类实例)所属的类(也就是AboutAsserts)开始,沿着继承链向上查找方法:先找AboutAsserts有没有name对应的方法,找到就直接执行;找不到才会去父类Koan、再往上到Object这些顶层类。你的代码里test_assert_truth刚好定义在AboutAsserts里,所以自然能被找到并调用。 send方法的本质:send是Ruby所有对象都自带的方法,它的作用是根据传入的方法名,在当前对象(self)的方法查找链中找到对应方法并执行,甚至能绕过private/protected的访问限制。这里的关键还是它基于当前实例的类型来查找,而不是定义send调用的类。
纠正你的误解
你觉得“父类方法本不应访问子类的方法”,其实这个说法不准确——不是父类方法主动去“访问”子类的方法,而是父类的方法在子类实例上运行时,调用的是该实例自身拥有的方法(这个方法由子类定义)。父类的代码并没有硬编码引用子类的方法,而是通过动态调用的方式,依赖实例的实际类型来找到对应的方法,这也是Ruby这类动态语言的灵活之处。
举个更简单的例子帮你理解:
class Parent def call_child_method(method_name) send(method_name) end end class Child < Parent def hello puts "Hello from Child!" end end child = Child.new child.call_child_method(:hello) # 会输出 "Hello from Child!"
这里call_child_method是父类的方法,但在子类实例上调用时,send(:hello)会找到子类定义的hello方法,原理和你遇到的Koans代码完全一致。
内容的提问来源于stack exchange,提问作者MIchal Skoda
相关产品推荐
相关产品推荐

