为什么 `Object.include` 和 `Fixnum.prepend` 的顺序很重要?
Why does order of `Object.include` and `Fixnum.prepend` matter?
我有这个模块:
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"
但是,如果我更改 prepend
和 include
的顺序,我的覆盖无效:
Object.include(MyMod)
Fixnum.prepend(MyMod)
123 + :test # error: -:10:in `+': :test can't be coerced into Fixnum (TypeError)
为什么include
和prepend
的顺序在这里有这个效果?
请参阅 Module#prepend_features 的文档:
When this module is prepended in another, Ruby calls prepend_features in this module, passing it the receiving module in mod. Ruby’s default implementation is to overlay the constants, methods, and module variables of this module to mod if this module has not already been added to mod or one of its ancestors. See also Module#prepend.
因此,prepend
仅在其参数尚未添加到接收者或其祖先之一时才会执行任何操作。由于 Object
是 Fixnum
的祖先,因此在 Object.include(MyMod)
之后调用 Fixnum.prepend(MyMod)
不会执行任何操作。
只是为了澄清@adrian 的回答。
没有模组的祖先链:
puts Fixnum.ancestors
# >> Fixnum
# >> Integer
# >> Numeric
# >> Comparable
# >> Object
# >> Kernel
# >> BasicObject
使用 "working" 改装
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
使用 "not working" 改装
Object.include(MyMod)
Fixnum.prepend(MyMod)
puts Fixnum.ancestors
# >> Fixnum
# >> Integer
# >> Numeric
# >> Comparable
# >> Object
# >> MyMod # fixnum will override this
# >> Kernel
# >> BasicObject
我有这个模块:
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"
但是,如果我更改 prepend
和 include
的顺序,我的覆盖无效:
Object.include(MyMod)
Fixnum.prepend(MyMod)
123 + :test # error: -:10:in `+': :test can't be coerced into Fixnum (TypeError)
为什么include
和prepend
的顺序在这里有这个效果?
请参阅 Module#prepend_features 的文档:
When this module is prepended in another, Ruby calls prepend_features in this module, passing it the receiving module in mod. Ruby’s default implementation is to overlay the constants, methods, and module variables of this module to mod if this module has not already been added to mod or one of its ancestors. See also Module#prepend.
因此,prepend
仅在其参数尚未添加到接收者或其祖先之一时才会执行任何操作。由于 Object
是 Fixnum
的祖先,因此在 Object.include(MyMod)
之后调用 Fixnum.prepend(MyMod)
不会执行任何操作。
只是为了澄清@adrian 的回答。
没有模组的祖先链:
puts Fixnum.ancestors
# >> Fixnum
# >> Integer
# >> Numeric
# >> Comparable
# >> Object
# >> Kernel
# >> BasicObject
使用 "working" 改装
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
使用 "not working" 改装
Object.include(MyMod)
Fixnum.prepend(MyMod)
puts Fixnum.ancestors
# >> Fixnum
# >> Integer
# >> Numeric
# >> Comparable
# >> Object
# >> MyMod # fixnum will override this
# >> Kernel
# >> BasicObject