我有一个类Base
,以及两个继承自Base
的类Derived
和Derived2
,它们都定义了一个函数foo
。
我还有一个模块Gen
,它是prepend
-艾德到Base
的,它也是prepend
-ed到Derived2
的,但不是Derived
的。
当我在Derived2
的示例上调用foo
时,结果就好像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]
2条答案
按热度按时间lnlaulya1#
为了帮助您理解,有一个方法
Class#ancestors
,它告诉您搜索方法的顺序。所以当你在一个对象上调用一个方法时,这个对象是这个类的一个示例,这个方法将按照这个顺序在相应的列表中被搜索。
super
只是说 “进一步遍历链并找到相同的方法”。对于
Base
,我们有foo
的两个实现-Base
中的和Gen
中的。Gen
的实现将首先被发现,因为模块是前置的。因此,在Base
的示例上调用它将调用Gen#foo
*=[S]
,其也将向上搜索该链(经由super
)=[from Base]
*。对于
Derived
,模块没有前置,并且我们有继承,因此,第一个发现的实现是在Derived
=Sfrom Derived
* 和super
中搜索来自Base
的链的其余部分(也就是上面的段落)=[from Base]from Derived
*。对于
Derived2
,模块是前置的,所以那里的方法会先被找到 *=[S]
*,然后那里的super
会在Derived2
*=[Sfrom Derived]
* 中找到下一个foo
,那里的super
会再次为Base
*=[[from Base]from Derived]
* 演示这个情况。**EDIT:**似乎直到最近,
prepend
都会先在祖先链中搜索,只有当模块不存在时才添加模块(类似于include
)。更令人困惑的是,如果您先创建父级,从父级继承,在子级中预挂,然后在父级中预挂,您将得到更新版本的结果。plupiseo2#
对于任何感兴趣的人,你可以实现类似这样的继承,基本上对于从
Base
继承的每个子类,都将Gen添加到它的祖先: