【问题标题】:Why does order of `Object.include` and `Fixnum.prepend` matter?为什么 `Object.include` 和 `Fixnum.prepend` 的顺序很重要?
【发布时间】:2015-08-14 16:15:27
【问题描述】:

我有这个模块:

module MyMod
  def +(other)
    puts "hello"
  end
end

这成功地将+ 覆盖为Fixnum

Fixnum.prepend(MyMod)

123 + :test  # outputs "hello"

假设我需要为Fixnum 和其他对象覆盖+ 运算符。这成功地覆盖了+Fixnum 和其他对象:

Fixnum.prepend(MyMod)
Object.include(MyMod)

123 + :test  # outputs "hello"

但如果我更改prependinclude 的顺序,我的覆盖无效:

Object.include(MyMod)
Fixnum.prepend(MyMod)

123 + :test  # error: -:10:in `+': :test can't be coerced into Fixnum (TypeError)

为什么includeprepend的顺序在这里会有这个效果?

【问题讨论】:

标签: ruby module


【解决方案1】:

查看Module#prepend_features的文档:

当这个模块被附加在另一个模块中时,Ruby 会在这个模块中调用 prepend_features,并将其传递给 mod 中的接收模块。 Ruby 的默认实现是将此模块的常量、方法和模块变量覆盖到 mod 如果此模块尚未添加到 mod 或其祖先之一。另请参阅 Module#prepend。

因此,prepend 仅在其参数尚未添加到接收器或其祖先之一时才执行任何操作。由于ObjectFixnum 的祖先,所以Fixnum.prepend(MyMod)Object.include(MyMod) 之后调用时不会执行任何操作。

【讨论】:

  • 哦,这么简单。非常感谢! SO 允许时,我会在一段时间内接受您的回答。
  • Andrian 回答了您的问题 (+1),但为什么要急于选择答案,以及为什么在其他人(不是我)无疑正在研究答案时承诺选择特定答案?快速选择可能会阻止其他答案,即使不是更好,也可能会提供有趣的观察结果。
  • @CarySwoveland 我发表了这样的声明,这样阿德里安就不用担心我了。不知道接受答案,因为在超时之前我无法接受。我接受答案的“策略”是接受第一个回答我的问题的答案——如果稍后有更好的答案出现,我很乐意支持它(我做到了)。即使不是第一个,也会对最详细的答案投赞成票吗?
  • 选择答案的个人政策似乎差异很大,从很少选择答案到总是选择最有帮助的答案,即使它是在提出问题数年后和 OP 之后提供的之前选择了一个答案。我建议至少等待几个小时,以免阻止其他答案以及出于对仍在准备答案的人的尊重。除此之外,人们仍然可以选择发布的第一个可接受的答案、最有帮助的答案等等。
【解决方案2】:

只是为了澄清@adrian 的回答。

没有修改的祖先链:

puts Fixnum.ancestors
# >> Fixnum
# >> Integer
# >> Numeric
# >> Comparable
# >> Object
# >> Kernel
# >> BasicObject

使用“工作”改装

Fixnum.prepend(MyMod)
Object.include(MyMod)

puts Fixnum.ancestors
# >> MyMod # here it is, having precedence over Fixnum#+
# >> Fixnum
# >> Integer
# >> Numeric
# >> Comparable
# >> Object
# >> MyMod # note the second copy. include(MyMod) doesn't check for duplicates, but it doesn't matter (here).
# >> Kernel
# >> BasicObject

带有“不工作”的改装

Object.include(MyMod)
Fixnum.prepend(MyMod)

puts Fixnum.ancestors
# >> Fixnum
# >> Integer
# >> Numeric
# >> Comparable
# >> Object
# >> MyMod  # fixnum will override this
# >> Kernel
# >> BasicObject

【讨论】:

    猜你喜欢
    • 2013-05-18
    • 1970-01-01
    • 2019-05-28
    • 2013-11-18
    • 1970-01-01
    • 2018-02-01
    • 2017-06-27
    • 1970-01-01
    • 2015-02-08
    相关资源
    最近更新 更多