如果mixin方法名称冲突,如何选择要调用的方法?

ben*_*ang 5 ruby

当您在具有方法名称冲突的类中包含模块时,它将使用该类定义的方法.有没有办法选择我想要运行哪一个?

module B
  def self.hello
    "hello B"
  end
end

class A
  include B
  def self.hello
     "hello A"
  end
end

A.hello #=> this prints "hello A", what if I want "hello B"?
Run Code Online (Sandbox Code Playgroud)

Ale*_*x D 12

Ben,当你hello在Ruby中调用一个方法(比如说)时,会发生以下情况:

  1. 如果接收者的本征类有一个hello被调用的方法,它将被调用.如果不:
  2. 如果接收者的类有一个hello被调用的实例方法,它将被调用.如果不:
  3. 如果接收者类包含的任何模块都有一个hello被调用的实例方法,那么它将被调用.如果有多个,最近包含的模块将"赢".除此以外:
  4. 如果接收者类的超类有一个hello被调用的实例方法,它将被调用.如果不:
  5. 如果接收者类的超类包含任何模块......
  6. (依此类推,对于超类的超类,一直到BasicObject ...)
  7. 如果没有hello找到调用的方法,则重复相同的过程method_missing,从本征类开始,然后是类,然后包含模块,然后是超类,然后是超类包含的模块......这个搜索总是成功,因为Kernel定义了一个默认实现的method_missing.

因此,要回答您的问题,如果调用了多个方法hello,则无法选择将调用哪个方法.上述方法查找规则决定调用哪一个.

但是:Ruby是一种非常灵活的语言,如果你发布关于你想做什么以及为什么做的更多细节,我可以帮你想到一种模拟所需效果的方法.

另一点:如果要将类方法从模块添加到类中,可以执行以下操作:

module B; def hello; "hello B"; end end
A.extend(B)
A.hello
=> "hello B"
Run Code Online (Sandbox Code Playgroud)

你有看到?当类includesa模块时,模块的实例方法成为类的实例方法.当一个类extendsa模块时,模块的实例方法成为类的类方法.


Tom*_*m L 1

它的设置方式无论如何都不会调用包含的模块的方法。尝试省略 A 中的 hello 方法,看看调用 时会发生什么A.hello。

这将包括 B 中的方法。可能有更简洁的方法来做到这一点。我刚刚从我的代码库中抄袭了它:

module B
  def self.included(base)
    base.extend Greetings
  end

  module Greetings
    def hello
      "hello B"
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

模块的方法将始终覆盖包含的模块的方法。这就是它应该工作的方式。但是,您可以有条件地返回 A 的 hello 值,如下所示:

module A
  include B

  def self.hello
    if show_hello_a?
      "hello A"
    else
      super
    end
  end

 def self.show_hello_a?
   false # insert an actual condition statement here
 end

end
Run Code Online (Sandbox Code Playgroud)