gpt4 book ai didi

ruby - Ruby 类层次结构中 `prepend` 的行为

转载 作者:太空宇宙 更新时间:2023-11-03 18:08:11 24 4
gpt4 key购买 nike

我有一个类 Base,以及两个继承自 Base 的类 DerivedDerived2。它们每个都定义了一个函数 foo

我还有一个模块 Gen,它是 prependBase 的。它也是 prependDerived2 但不是 Derived

当我在 Derived2 的实例上调用 foo 时,结果就好像 Gen 模块只是prepend-ed 到 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]

最佳答案

为了帮助大家理解,有一个方法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 )= [from Base] .

对于 Derived , 模块没有前置,我们有继承。因此,第一个找到的实现是在Derived中。 = Sfrom Derived super将搜索来自 Base 的链的其余部分(也就是上面的段落播放完)= [from Base]from Derived .

对于 Derived2 , 模块是前置的,所以首先会找到那里的方法 = [S] 。然后 super那里会找到下fooDerived2 = [Sfrom Derived] ,以及 super Base的情况会出来的再次 = [[from Base]from Derived] .


编辑: 似乎直到最近,prepend将首先在祖先链中搜索并仅在模块不存在时才添加模块(类似于 include )。更令人困惑的是,如果您首先创建父级,从它继承,在子级中添加前缀,然后在父级中添加,您将得到较新版本的结果。

关于ruby - Ruby 类层次结构中 `prepend` 的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40013933/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com