[英]Behaviour of `prepend` in Ruby class hierarchies
I have a class Base
, and two classes Derived
and Derived2
that inherit from Base
. 我有一个类Base
,以及两个继承自Base
Derived
和Derived2
类。 They each have a function foo
defined in them. 它们每个都有一个定义的函数foo
。
I also have a module Gen
which is prepend
-ed to Base
. 我也有一个模块Gen
其prepend
-ed到Base
。 It is also prepend
-ed to Derived2
but not to Derived
. 它也是Derived2
prepend
,但不是Derived
。
When I call foo
on an instance of Derived2
, the result is as if the Gen
module was only prepend
-ed to Base
and not to Derived2
also. 当我在Derived2
一个实例上调用foo
时,结果就好像Gen
模块只是prepend
到Base
而不是Derived2
。 Is this the expected behavior? 这是预期的行为吗?
Here is the code for the above scenario: 以下是上述场景的代码:
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"
I expected the last of the above statement to output: 我期望输出上述语句的最后一个:
[[from Base]from Derived]
To help you understand, there is a method Class#ancestors
, which tells you the order in which a method will be searched for. 为了帮助您理解,有一个方法Class#ancestors
,它告诉您搜索方法的顺序。 In this case: 在这种情况下:
Base.ancestors # => [Gen, Base, Object, Kernel, BasicObject]
Derived.ancestors # => [Derived, Gen, Base, Object, Kernel, BasicObject]
Derived2.ancestors # => [Gen, Derived2, Gen, Base, Object, Kernel, BasicObject]
So when you call a method on an object that is an instance of said class, that method will be searched in the corresponding list in that order. 因此,当您在作为所述类的实例的对象上调用方法时,将按该顺序在相应的列表中搜索该方法。
super
just says "go traverse the chain further and find me the same method" . super
只是说“进一步遍历链条,找到我同样的方法” 。 For Base
, we have two implementations of foo
- that in Base
and that in Gen
. 对于Base
,我们有两个foo
实现 - 在Base
和Gen
。 The Gen
one will be found first as the module was prepended. 在模块被预先安装之前,将首先找到第一Gen
。 Therefore calling it on an instance of Base
will call Gen#foo
= [S]
, which will search up the chain as well (via super
) = [from Base]
. 因此,在Base
的实例上调用它将调用Gen#foo
= [S]
,它也将搜索链(通过super
) = [from Base]
。
For Derived
, the module wasn't prepended, and we have inheritance. 对于Derived
,模块没有前置,我们有继承。 Therefore, the first found implementation is that in Derived
= Sfrom Derived
and super
will search the rest of the chain that comes from Base
(aka the above paragraph is played out) = [from Base]from Derived
. 因此,第一个找到的实现是在Derived
= Sfrom Derived
, super
将搜索来自Base
的其余链(也就是上面的段落被播放) = [from Base]from Derived
。
For Derived2
, the module is prepended, so the method there will be found first = [S]
. 对于Derived2
,模块是前置的,因此首先会找到方法= [S]
。 Then the super
there will find the next foo
in Derived2
= [Sfrom Derived]
, and the super
there will play out the situation for Base
again = [[from Base]from Derived]
. 然后super
会在Derived2
= [Sfrom Derived]
找到下一个foo
,而super
将会再次显示Base
的情况= [Sfrom Derived]
[[from Base]from Derived]
。
EDIT: It seems that up until very recently, prepend
would first search in the ancestors chain and add the module only if it is not already present (similarly to include
). 编辑:似乎直到最近, prepend
将首先在祖先链中搜索并仅在模块尚未存在时添加模块(类似于include
)。 To make it even more confusing, if you first create the parent, inherit from it, prepend in the child and then prepend in the parent, you will get the result of newer versions. 更令人困惑的是,如果您首先创建父级,继承它,在子级中添加前置,然后在父级中添加,您将获得更新版本的结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.