我有一个班级Base
,以及两个继承自Derived
的班级Derived2
和Base
。它们每个都有一个函数foo
。
我还有一个Gen
模块prepend
- 编辑为Base
。它也是prepend
- Derived2
但不是Derived
。
当我在foo
的实例上调用Derived2
时,结果就好像Gen
模块仅prepend
- 编辑为Base
而不是到Derived2
也是。这是预期的行为吗?
以下是上述方案的代码:
module Gen
def foo
val = super
'[' + val + ']'
end
end
class Base
prepend Gen
def foo
"from Base"
end
end
class Derived < Base
def foo
val = super
val + "from Derived"
end
end
class Derived2 < Base
prepend Gen
def foo
val = super
val + "from Derived"
end
end
Base.new.foo # => "[from Base]"
Derived.new.foo # => "[from Base]from Derived"
Derived2.new.foo # => "[from Base]from Derived"
我期望输出上述语句的最后一个:
[[from Base]from Derived]
答案 0 :(得分:3)
为了帮助您理解,有一种方法Class#ancestors
,它告诉您搜索方法的顺序。在这种情况下:
Base.ancestors # => [Gen, Base, Object, Kernel, BasicObject]
Derived.ancestors # => [Derived, Gen, Base, Object, Kernel, BasicObject]
Derived2.ancestors # => [Gen, Derived2, Gen, Base, Object, Kernel, BasicObject]
因此,当您在作为所述类的实例的对象上调用方法时,将按相应的顺序在该对应的列表中搜索该方法。
super
只是说“进一步遍历链条并找到相同的方法”。对于Base
,我们有两个foo
实现 - Base
和Gen
。在模块被预先添加之前,将首先找到Gen
。因此,在Base
的实例上调用它会调用Gen#foo
= [S]
,这也将搜索链(通过super
)< EM> = [from Base]
对于Derived
,模块没有前置,我们有继承。因此,第一个找到的实现是Derived
= Sfrom Derived
和super
将搜索来自Base
的其他链(又名{播放上面的段落) = [from Base]from Derived
。
对于Derived2
,模块是前置的,因此首先会找到 = [S]
的方法。然后,super
会在foo
= Derived2
中找到下一个[Sfrom Derived]
,super
将会发现情况再次Base
= [[from Base]from Derived]
。
编辑:似乎直到最近,prepend
才首先在祖先链中进行搜索并仅在模块尚未存在时添加模块(类似于include
})。为了让它更令人困惑,如果你第一次创建父项,从它继承,在子项之前添加,然后在父项之前,你将获得更新版本的结果。