Calling “super” keyword with modules and inheritance
我认为在一个类中包含一个作为 mixin 的模块”将功能”添加到了类中。
我不明白为什么这不能按预期工作:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
module A
def blah super if defined?(super) puts“hello, world!” end end class X class Y < X y = Y.new |
我期待”y”调用它的超级 blah()(因为它包含在 X 类中?)但我得到了:
test.rb:3:in blah: super: no superclass method `blah’
您会遇到 Ruby 对象层次结构的细微差别以及方法查找如何与包含的模块交互。
当您调用对象的方法时,Ruby 会遍历对象类的 ancestors 列表,寻找响应该方法的祖先类或模块。当您在该方法中调用 super 时,您实际上是在继续沿着 ancestors 的树向上走,寻找响应相同方法名称的下一个对象。
X 和 Y 类的祖先树如下所示:
1
2 |
p X.ancestors #=> [ X, A, Object, Kernel, BaseObject ]
p Y.ancestors #=> [ Y, X, A, Object, Kernel, BaseObject ] |
问题在于,在子类中第二次 include 执行该模块时,不会在祖先链中注入该模块的第二个副本。
实际上,当您调用 Y.new.blah 时,Ruby 开始寻找响应 blah 的类。它经过 Y 和 X,并降落在引入 blah 方法的 A 上。当 A#blah 调用 super 时,祖先列表中的”指针”已经指向 A,Ruby 从该点继续寻找响应 blah 的另一个对象,从 Object 开始,Kernel,然后是 BaseObject。这些类都没有 blah 方法,因此您的 super 调用失败。
如果一个模块 A 包含一个模块 B,然后一个类同时包含模块 A 和 B,也会发生类似的情况。 B 模块未包含两次:
1
2 3 4 5 6 7 8 9 |
module A; end
module B; include A; end class C p C.ancestors # [ C, B, A, Object, Kernel, BaseObject ] |
请注意,它是 C, B, A,而不是 C, A, B, A。
其意图似乎是允许您在任何 A 的方法中安全地调用 super,而不必担心消费类层次结构可能会无意中包含两次 A。
有一些实验证明了这种行为的不同方面。第一个是给 Object 添加一个 blah 方法,它允许 super 调用通过:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
class Object; def blah; puts“Object::blah”; end; end
module A class X class Y < X Y.new.blah # Output |
第二个实验是使用两个模块,BaseA 和 A,这确实会导致模块在 ancestors 链中正确插入两次:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
module BaseA
def blah puts“BaseA::blah” end end module A class X class Y < X p Y.ancestors # [ Y, A, X, BaseA, Object, …] # Output |
第三个实验使用 prepend 而不是 include,它将模块放置在 ancestors 层次结构中的对象前面,并且有趣地插入了模块的副本。这使我们能够到达有效地 Y::blah 调用 X::blah 的地步,但由于 Object::blah 不存在而失败:
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
require ‘pry’
module A class X class Y < X p Y.ancestors # [ A, Y, A, X, Object, … ] # Output |
- 非常有趣和有启发性。你在开场白的开头所说的”我无法完全解释”是什么意思。
- @CarySwoveland我的意思是这个答案依赖于似乎支持该假设的假设和实验,而不是权威解释和支持文档的链接。
- @CarySwoveland 无论如何,我稍微更新了措辞。
- 这可能是您正在寻找的关于方法查找的参考资料的一部分:ruby-doc.org/core/doc/syntax/…
来源:https://www.codenong.com/41451292/