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 include A end class Y < X include A end y = Y.new y.blah |
我期待"y"调用它的超级 blah()(因为它包含在 X 类中?)但我得到了:
test.rb:3:in blah: super: no superclass method `blah'
您会遇到 Ruby 对象层次结构的细微差别以及方法查找如何与包含的模块交互。
当您调用对象的方法时,Ruby 会遍历对象类的
1 2 | p X.ancestors #=> [ X, A, Object, Kernel, BaseObject ] p Y.ancestors #=> [ Y, X, A, Object, Kernel, BaseObject ] |
问题在于,在子类中第二次
实际上,当您调用
如果一个模块
1 2 3 4 5 6 7 8 9 | module A; end module B; include A; end class C include A include B end p C.ancestors # [ C, B, A, Object, Kernel, BaseObject ] |
请注意,它是
其意图似乎是允许您在任何
有一些实验证明了这种行为的不同方面。第一个是给 Object 添加一个
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 def blah puts"A::blah" super end end class X include A end class Y < X include A end Y.new.blah # Output # A::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 | module BaseA def blah puts"BaseA::blah" end end module A def blah puts"A::blah" super end end class X include BaseA end class Y < X include A end p Y.ancestors # [ Y, A, X, BaseA, Object, ...] Y.new.blah # Output # A::blah # BaseA::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 def blah puts"A::blah" begin super rescue puts"no super" end end end class X prepend A end class Y < X prepend A end p Y.ancestors # [ A, Y, A, X, Object, ... ] Y.new.blah # Output # A::blah (from the A before Y) # A::blah (from the A before X) # no super (from the rescue clause in A::blah) |