当存在mixin方法名称冲突时,如何选择要调用的方法



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

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"?

Ben,当您在Ruby中调用一个方法(假设它是hello)时,会发生以下情况:

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

因此,为了回答您的问题,如果有不止一个名为hello的方法,您无法选择将调用哪一个。上面描述的方法查找规则决定将调用哪一个。

HOWEVER:Ruby是一种非常灵活的语言,如果你发布更多关于你想做什么以及为什么要做的细节,我可能会帮助你想出一种方法来模拟想要的效果。

另一点:如果你想把类方法从一个模块添加到一个类中,你可以这样做:

module B; def hello; "hello B"; end end
A.extend(B)
A.hello
=> "hello B"

你看到了吗?当类include是一个模块时,该模块的实例方法将成为该类上的实例方法。当类extend是一个模块时,该模块的实例方法将成为该类上的类方法。

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

这将包括B的方法。可能有一种更简洁的方法。我刚从我的代码库中剽窃了它:

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

模块的方法将始终覆盖包含的模块的方法。这就是它应该工作的方式。然而,您可以有条件地返回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

当您调用A.Hello时,所发生的只是将消息"Hello"传递给A对象。然后,A对象必须确定如何处理该消息。它将首先查看自己的方法,以确定是否有一个名为"hello"的方法,然后再查看它的父方法和包含的模块以获得"hello"方法。

虽然从技术上讲,您可以使用A.祖先来查看B是A的祖先,并调用它的hello方法,但这将违反A作为对象的抽象。

允许调用这两个方法的正确方法是在A中创建另一个调用B.hello的方法,或者将A.hello命名为其他名称,这样它就不会覆盖B.hello功能。

编辑:因为你已经在A中包含了B,所以在A中创建一个调用B的hello的方法就像添加一个调用B.hello 的方法一样简单

def self.hello2
  B.hello
end

最新更新