加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ruby – 使用模块和继承调用“超级”关键字

发布时间:2020-12-17 03:50:25 所属栏目:百科 来源:网络整理
导读:我认为在类中包含一个模块作为mixin“将函数添加到”类中. 我不明白为什么这不能按预期工作: module A def blah super if defined?(super) puts "hello,world!" endendclass X include Aendclass Y X include Aendy = Y.newy.blah 我期待“y”调用它的超级b
我认为在类中包含一个模块作为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类中?)但我得到了:

test.rb:3:in blah: super: no superclass method `blah’

解决方法

您正在遇到Ruby的对象层次结构的细微差别以及方法查找如何与包含的模块交互.

当您在对象上调用方法时,为对象的类调用Ruby walks over the ancestors list,查找响应该方法的祖先类或模块.当您在该方法中调用super时,您将有效地继续沿着祖先树行走,寻找响应相同方法名称的下一个对象.

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)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读