Ruby 可以通过包含模块来重写方法吗?

Ruby 可以通过包含模块来重写方法吗?,ruby,Ruby,可能重复: 下面是一些代码: 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是否会阻止重写先前定义的方法?您的包含调用不会像您所想的那样。。。试一下Foo.send(:

可能重复:

下面是一些代码:

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是否会阻止重写先前定义的方法?

您的包含调用不会像您所想的那样。。。试一下Foo.send(:extend,M)我不太明白你的问题。你认为在这里“阻止”的到底是什么?是谁阻止的

这正是它应该如何工作的
Module#include
mixes在模块中作为它所混入的任何类的直接超类
M
Foo
的超类,因此
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]
class-FooS;结束
模块M;结束
Foo类[Foo,M,FooS,Object,Kernel,BasicObject]

重新表述@Jorg的答案:

如果你这样做

Foo.send(:include,M)
Foo.ancestors
你回来

[Foo, M, Object, Kernel, BasicObject]
这意味着当调用
bar
时,它会首先查看是否存在
Foo\bar
,只有当它不存在时,才会尝试查看
M\bar
(然后是
对象
内核
基本对象
,然后调用
方法


就个人而言,我不介意在查看
Foo
之前先查看
M
的功能。我听说有人说要在Ruby 2.0中添加这样的功能,但现在这对您没有帮助。

我的理解是extend将方法添加为类方法。不将最后两行替换为puts Foo.methods.grep(/bar/).inspect Foo.send(:extend,M)Foo.new.bar puts Foo.methods.grep(/bar/).inspect,您会看到它已添加到类中。我不知道为什么这个评论系统不允许回车,我也不明白,我认为这是问题的核心;如果你把include放在类中,这应该行得通……啊,我不知道模块中的include mixes作为它被混合到的对象的直接超类,而不是类本身。我还是不明白。所以如果我有类FooS,并且Foo是FooS的子类,你是说bar现在将在FooS中定义吗?对我来说似乎没有意义,也没有意义。我一定是误解了你的意思。@LeftHem:嗯?为什么
bar
会神奇地被定义在它不存在的地方?如果将
FooS
作为
Foo
的超类添加到组合中,则仍然只有两个
bar
的定义,一个在
Foo
中,另一个在
M
中。为什么其中一个会突然跳来跳去
M
仍然作为
Foo
的一个直接超类插入(因此,显然,作为
FooS
的一个子类插入),而
Foo#bar
的定义仍然覆盖
M#bar
的定义,因为
Foo
仍然是
M
的一个子类。在
Foo
上面插入一个超类不会改变什么,毕竟,以前已经有一个超类:
Object
。我的坏——“作为一个直接超类”,而不是“在一个直接超类中”。现在我明白了,“继承就是这样工作的”是不公平的,因为Ruby完全抛弃了传统的继承……如果包含多个模块呢?哪一个现在是直接超类?假设Ruby类只能从一个基类继承?我认为
Module#prepend
(这就是您所说的)实际上已经在YARV trunk中实现了。与其他东西(特别是改进)不同,它完全没有争议,而且很容易实现,因此它几乎可以保证最终会出现在Ruby 2.0规范中。事实上,由于向后兼容,我在1.9.3中看到它也不会感到太惊讶(如果将来会有一个的话)。@Jorg:为什么不会有1.9.3呢?他们想直接进入2.0吗?
x=Foo.new;x、 扩展M;x、 bar
将覆盖该方法,模块方法中的
super
将调用实例方法。详情:Meh。我怎么能忘记那个?