【问题标题】:Can you override a method by including a module? [duplicate]你可以通过包含一个模块来覆盖一个方法吗? [复制]
【发布时间】:2011-06-02 23:46:50
【问题描述】:

可能重复:
Overriding method by another defined in module

这里有一些代码:

class Foo
  def bar
    puts "Original bar"
  end
end

module M
  def bar
    puts "Called M::bar"    
  end
end

Foo.send(:include,M)
Foo.new.bar
# => Original bar

当“包含”同名方法时,ruby 是否会阻止覆盖先前定义的方法?

【问题讨论】:

  • 嗯。我怎么能忘记那个?

标签: ruby


【解决方案1】:

我不太明白你的问题。您认为究竟是什么在这里被“阻止”了,由谁来“阻止”?

这正是它应该如何工作的。 Module#include 混合在模块中,作为它被混合到的任何类的直接超类。 MFoo 的超类,所以Foo#bar 覆盖M#bar,因为继承就是这样工作的:子类覆盖超类,而不是相反。这里没有什么被“阻止”,当然你仍然可以在Foo的子类中覆盖Foo#bar

你可以清楚地看到祖先:

class FooS; end
module M; end
class Foo < FooS; include M end

Foo.ancestors # => [Foo, M, FooS, Object, Kernel, BasicObject]

【讨论】:

  • 啊,我不知道 Module#include 混合在模块中作为它被混合的直接超类,而不是类本身。我其实还是不明白。所以如果我有 FooS 类并且 Foo 是 FooS 的子类,你是说 bar 现在将在 FooS 中定义吗?对我来说似乎也没有意义。我一定是误解了你在说什么。
  • @LeftHem:嗯?为什么bar 会神奇地被定义在某个不是的地方?如果将FooS 作为Foo 的超类添加到组合中,那么仍然只有两个bar 定义,一个在Foo 中,一个在M 中。为什么其中一个会突然跳来跳去? M still 被插入为Foo 的直接超类(因此,显然,作为FooS 的子类)和Foo#bar still 的定义覆盖M#bar 的定义,因为Foo仍然M 的子类。在Foo 上面插入一个超类并没有改变,毕竟之前已经有一个超类:Object
  • 我的错 - “作为直接超类”,而不是“在直接超类中”。现在我明白了。
  • “这就是继承的工作方式”并不公平,因为 Ruby 完全抛弃了传统继承......
  • 如果您包含多个模块怎么办?现在哪个是直接超类?鉴于 Ruby 类只能从一个基类继承?
【解决方案2】:

改写@Jorg 的回答:

如果你这样做

Foo.send(:include,M)
Foo.ancestors

你回来了

[Foo, M, Object, Kernel, BasicObject]

这意味着当bar 被调用时,它首先查看是否有Foo#bar,只有当它不存在时才会尝试查看M#bar(然后是ObjectKernel , BasicObject 然后调用method_missing)。

就个人而言,我不介意先查看M,然后再查看Foo。我听说有人谈论要在 Ruby 2.0 中添加执行此操作的功能,但现在这对您没有帮助。

【讨论】:

  • 我认为Module#prepend(这就是你所说的)实际上已经在 YARV 中继中实现了。与其他一些东西(特别是细化)不同,它完全没有争议并且非常容易实现,因此几乎可以保证它实际上最终会出现在 Ruby 2.0 规范中。事实上,由于向后兼容,我不会对在 1.9.3 中看到它感到惊讶(如果有的话)。
  • @Jorg:为什么没有 1.9.3?他们是否考虑直接进入 2.0?
  • x = Foo.new; x.extend M; x.bar 将覆盖该方法,而模块方法中的super 将调用实例方法。详情:subinterest.com/rubies-in-the-rough/15-learn-to-love-mix-ins
【解决方案3】:

您的 include 调用并没有按照您的想法...尝试Foo.send(:extend,M)

【讨论】:

  • 我的理解是extend将方法添加为类方法。不?用 puts Foo.methods.grep( /bar/).inspect Foo.send(:extend,M) Foo.new.bar puts Foo.methods.grep( /bar/).inspect 替换最后两行,你会看到它被添加到类中。不知道为什么这个评论系统不允许回车
  • 看这个,我也有一些不明白的地方,我认为这是问题的核心;如果您将 include 放入类中,这应该可以工作...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-07
  • 2021-11-20
  • 2021-11-15
  • 2018-06-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多