我有这个模块:
module MyMod
def +(other)
puts "hello"
end
end
这已成功覆盖+
的{{1}}:
Fixnum
我们说我需要为Fixnum.prepend(MyMod)
123 + :test # outputs "hello"
和其他对象覆盖+
运算符。这会成功覆盖Fixnum
和其他对象的+
:
Fixnum
但是,如果我更改Fixnum.prepend(MyMod)
Object.include(MyMod)
123 + :test # outputs "hello"
和prepend
的顺序,则我的覆盖无效:
include
为什么Object.include(MyMod)
Fixnum.prepend(MyMod)
123 + :test # error: -:10:in `+': :test can't be coerced into Fixnum (TypeError)
和include
的顺序会产生此效果?
答案 0 :(得分:4)
请参阅Module#prepend_features的文档:
当这个模块被放在另一个模块中时,Ruby在这个模块中调用prepend_features,并在mod中传递接收模块。 Ruby的默认实现是将此模块的常量,方法和模块变量覆盖到mod ,如果此模块尚未添加到mod或其祖先之一。另见Module#prepend。
因此,prepend
只有在其参数尚未添加到接收器或其祖先之一时才会执行任何操作。由于Object
是Fixnum
的祖先,Fixnum.prepend(MyMod)
在Object.include(MyMod)
之后调用时没有做任何事情。
答案 1 :(得分:4)
只是为了澄清@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
“不工作”modding
Object.include(MyMod)
Fixnum.prepend(MyMod)
puts Fixnum.ancestors
# >> Fixnum
# >> Integer
# >> Numeric
# >> Comparable
# >> Object
# >> MyMod # fixnum will override this
# >> Kernel
# >> BasicObject