ruby – 使用模块和继承调用“超级”关键字
我认为在类中包含一个模块作为mixin“将函数添加到”类中.
我不明白为什么这不能按预期工作: 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类中?)但我得到了:
解决方法
您正在遇到Ruby的对象层次结构的细微差别以及方法查找如何与包含的模块交互.
当您在对象上调用方法时,为对象的类调用Ruby walks over the X和Y类的祖先树如下所示: p X.ancestors #=> [ X,A,Object,Kernel,BaSEObject ] p Y.ancestors #=> [ Y,X,BaSEObject ] 问题是在子类中第二次包含模块不会在祖先链中注入模块的第二个副本. 实际上发生的事情就是当你调用Y.new.blah时,Ruby开始寻找一个响应blah的类.它走过Y和X,然后登陆A,它引入了blah方法.当A#blah调用super时,你的祖先列表中的“指针”已经指向A,并且Ruby从该点继续寻找另一个响应blah的对象,从Object,Kernel开始,然后是BaSEObject.这些类都没有blah方法,所以你的超级调用失败了. 如果模块A包含模块B,则类似的事情发生,然后类包括模块A和B.B模块不包括两次: module A; end module B; include A; end class C include A include B end p C.ancestors # [ C,B,BaSEObject ] 注意它是C,而不是C,A. 意图似乎是允许您在A的任何方法中安全地调用super,而不必担心类层次结构可能无意中包含A两次. 有一些实验证明了这种行为的不同方面.第一个是向Object添加一个blah方法,它允许超级调用传递: 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 第二个实验是使用两个模块,BaseA和A,它确实使模块在祖先链中正确插入两次: 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,BaseA,...] Y.new.blah # Output # A::blah # BaseA::blah 第三个实验使用prepend而不是include,它将模块放在祖先层次结构中的对象前面,有趣的是插入模块的副本.这允许我们达到有效Y :: blah调用X :: blah的地步,因为Object :: blah不存在而失败: 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,... ] 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) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |