Ruby 我不知道';我不明白mixin是如何工作的
我有两个模块:Ruby 我不知道';我不明白mixin是如何工作的,ruby,Ruby,我有两个模块: module A def name puts "REAL" end end module B def name puts "FAKE" end end 当我将它们包括在我的课堂中时,如下所示: class ABC include A include B end class ABC include B include A end ABC.new.name的输出为: "FAKE" "REAL" 但当我包括如下模块时: cla
module A
def name
puts "REAL"
end
end
module B
def name
puts "FAKE"
end
end
当我将它们包括在我的课堂中时,如下所示:
class ABC
include A
include B
end
class ABC
include B
include A
end
ABC.new.name
的输出为:
"FAKE"
"REAL"
但当我包括如下模块时:
class ABC
include A
include B
end
class ABC
include B
include A
end
ABC.new.name
的输出为:
"FAKE"
"REAL"
我不明白为什么会这样。有人能帮我理解这一点吗?当两个模块用相同的名称定义方法时,实际保留在类中的方法是最后包含的方法。当两个模块用相同的名称定义方法时,实际保留在类中的方法是最后包含的方法。我不明白这种行为:
irb(main):121:0* module A
irb(main):122:1> def name
irb(main):123:2> puts "REAL"
irb(main):124:2> end
irb(main):125:1> end
=> nil
irb(main):128:0* module B
irb(main):129:1> def name
irb(main):130:2> puts "FAKE"
irb(main):131:2> end
irb(main):132:1> end
=> nil
irb(main):133:0> class ABC
irb(main):134:1> include A
irb(main):135:1> include B
irb(main):136:1> end
=> ABC
irb(main):137:0> ABC.new.name
FAKE
=> nil
irb(main):143:0> class XYZ
irb(main):144:1> include B
irb(main):145:1> include A
irb(main):146:1> end
=> XYZ
irb(main):147:0> XYZ.new.name
REAL
=> nil
这是有意义的——包含的最后一个模块可以定义该方法。也许您的程序中还有其他问题?我不明白这种行为:
irb(main):121:0* module A
irb(main):122:1> def name
irb(main):123:2> puts "REAL"
irb(main):124:2> end
irb(main):125:1> end
=> nil
irb(main):128:0* module B
irb(main):129:1> def name
irb(main):130:2> puts "FAKE"
irb(main):131:2> end
irb(main):132:1> end
=> nil
irb(main):133:0> class ABC
irb(main):134:1> include A
irb(main):135:1> include B
irb(main):136:1> end
=> ABC
irb(main):137:0> ABC.new.name
FAKE
=> nil
irb(main):143:0> class XYZ
irb(main):144:1> include B
irb(main):145:1> include A
irb(main):146:1> end
=> XYZ
irb(main):147:0> XYZ.new.name
REAL
=> nil
这是有意义的——包含的最后一个模块可以定义该方法。也许您的节目中还有其他一些内容?让我们退一步:什么是混音?Gilad Bracha没有发明mixin(它们是作为Lisp机器Lisp面向对象扩展中的设计模式发明的),但他写了一篇关于它们的开创性论文(他的博士论文),在论文中他定义了什么是mixin,并表明mixin组合包含了所有其他形式的经典继承。根据本文,mixin是由其超类参数化的类。因此,可以将mixin看作一个函数::
类→ 类
这到底是什么意思?因为mixin是由它的超类参数化的,所以它不知道它的超类。当mixin被混合到一个类中时,它将被提供其超类。mixin可以在继承图中多次混合,每次都使用不同的超类。注意:这正是双重到多重继承:在多重继承中,一个类只存在一次,但可能有许多超类。在mixin组合中,mixin存在很多次,但每个实例只有一个超类
这在Ruby中是如何工作的
让我们再次退一步,看看Ruby中的模块在操作上是什么样子的。模块包括:
- 方法表
- 固定的桌子
- 类变量表
- 超类指针
M
包含到类C
中时,会发生什么
class C
include M
end
首先,这是一种和其他方法一样的方法。这没什么特别的。其默认实现看起来有点像这样:
class Module
def include(mod)
mod.append_features(self)
included(mod)
end
end
ABC → Object
最后,它调用了hook方法,但我们在这里忽略它。它将实际的mixin组合委托给mixin。(这意味着mixin可以通过覆盖默认的模块#append_功能
,来决定它要以何种方式进行混合!然而,这很少使用,但例如ActiveSupport::Concern
将其用于元编程。)
现在我们已经把这个问题推开了。你做什么?好吧,它还是一个和其他方法一样的方法,它可以被覆盖,可以被修补,可以被删除(这不是一个好主意!)。但是,它的默认实现不能用Ruby表示
它的作用是:
M'
M'
的方法表指针设置为M
的方法表(常量表和类变量表同上)M′
的超类指针设置为C
的超类C
的超类指针设置为M'
M′
成为C
的新超类,使C
的旧超类成为M′
的超类,或者换一种方式,在继承树的C
正上方插入M′
为什么要这样做?因为它使方法查找非常简单:方法查找算法根本不需要了解mixin,它仍然是与在没有mixin的语言中看起来完全相同的算法:
method\u missing
,然后raise
异常),而在步骤2中则是一个循环。紧凑的简单循环很好,毕竟,方法查找是面向对象语言实现中最常执行的操作
现在,你可能会说,“等等,我问了C
它的超类
,它不返回M′
,它返回Object
!”是的,这是真的。但是,它不只是返回超类指针,与方法查找算法不同,它确实知道mixin。或者,更确切地说,它知道YARV的开发人员称之为虚拟类,并且知道在返回超类时跳过虚拟类。虚拟类是YARV内部使用的名称。它指的是包含类(即我上面描述的类,它们是在include
期间创建的)和单例类。反射方法知道如何特别处理它们,例如,忽略它们,知道返回模块M
,而不是包含类M'
我将在这里暂停,让您在一张纸上运行代码的append\u features
算法和方法查找算法,这样您就可以自己弄清楚为什么会看到所看到的结果
好的,那么,在你的例子中是怎样的
我们有一个类ABC
,它以Object
作为它的