在多个 Class#extend 通话中

On multiple Class#extend calls

考虑来自 this article 的代码:

class Coffee
  def cost
    2
  end
end

module Milk
  def cost
    super + 0.4
  end
end

module Sugar
  def cost
    super + 0.2
  end
end

coffee = Coffee.new
coffee.extend(Milk)
coffee.extend(Sugar)
coffee.cost   # 2.6, while I expected 2.2

它是 2.6 而不是 2.2 的原因是因为每次调用 extend 都会将一个模块添加到实例单例 class 祖先链中,如下所述。

你总是只有 #cost 被未来的参数修改 - 这不是被覆盖的问题:

coffee = Coffee.new
#cost is 2
coffee.extend(Milk)
#cost is 2.4
coffee.extend(Sugar)
#cost is 2.6

文章说此实现与他们提供的其他基于继承的示例相同。

extend 添加到祖先列表中,它不会替换任何现有的祖先 - 如果您在第二次扩展后检查 coffee.singleton_class.ancestors,您会看到它同时包含 MilkSugar

如果你是运行 2.2,你可以使用新的super_method方法检查一下:

coffee.method(:cost) => #<Method: Coffee(Sugar)#cost>

这表明,如果您调用 'cost',您首先会转到 'Sugar' 模块的实现

coffee.method(:cost).super_method => #<Method: Coffee(Milk)#cost>

这表明在Sugar#cost你调用super然后你会跳转到Milk

提供的方法

最后

coffee.method(:cost).super_method.super_method => #<Method: Coffee#cost>

当您从那里调用 super 时,您最终进入基础 class 实现