当模块在Ruby中扩展时,内部会发生什么?
当一个模块包含在一个类中时,将创建一个匿名代理类并将其设置为MyClass的超类当模块在Ruby中扩展时,内部会发生什么?,ruby,Ruby,当一个模块包含在一个类中时,将创建一个匿名代理类并将其设置为MyClass的超类 Foo = Module.new class MyClass include Foo end 但是当模块被扩展时,内部会发生什么?Ruby如何处理这个问题 在Ruby中扩展模块时,内部会发生什么 当模块M包含在类C中时,匿名代理类⟦M′⟧(称为include类)时,其方法表指针指向M的方法表。(常数表和模块变量也是如此。)⟦M′⟧的超类设置为C的超类,C的超类设置为⟦M′⟧ 此外,如果M包括其他模块,则递归
Foo = Module.new
class MyClass
include Foo
end
但是当模块被扩展时,内部会发生什么?Ruby如何处理这个问题
在Ruby中扩展模块时,内部会发生什么
当模块M
包含在类C
中时,匿名代理类⟦M′⟧创建code>(称为include类)时,其方法表指针指向M
的方法表。(常数表和模块变量也是如此。)⟦M′⟧
的超类设置为C
的超类,C
的超类设置为⟦M′⟧代码>
此外,如果M
包括其他模块,则递归应用该过程
实际上,这只是默认行为。真正发生的是include
调用M.append\u features(C)
,您可以通过重写该方法自定义所有行为
我觉得很可读。我想你问的是对象#扩展
因此,通过extend
,我可以将任何模块的方法包含到该对象中。
例如,我有一个名为HelperModule的模块:
MyClass.ancestors => [MyClass, Foo, ...]
用法示例1:
用法示例2:
内部,根据:
Object#extend()只是一个快捷方式,在接收器的本征类中包含一个模块。
ruby方法调用的简要说明:
查找对象的类,查看其中定义的方法
查找该类的超类,查看其中定义的方法
关于特征类和方法调用路径的详细解释,请参考这本很棒的书
谢谢obj.extend SomeModule
与obj.eigenclass.include SomeModule
相同(注意:这只是伪代码,但你会明白的…。简而言之,Ruby的include
方法将模拟继承:它将允许include类访问包含的模块的实例方法,变量和常量,就好像它们是在include类本身中定义的一样。Ruby通过创建一个匿名代理类(称为特征类或单例类)来实现这一点,正如您所提到的,该类引用包含的模块,并将其作为直接超类插入包含类的祖先中。这就是Ruby中的mixin
但是,使用extend
,与singleton类的交互会稍微多一些:
obj
|
| class
| superclass superclass
---> ObjectClass --------------> SuperClass1 --------------> SuperClass2 ....
在Bar
中扩展Foo
与
module Foo
def baz
'baz'
end
end
module Blah
def blah
'blah'
end
end
class Bar
extend Foo
include Blah
def self.magic
'magic'
end
end
这意味着它是Bar
的单例类,其中基本上嵌入了Foo
的方法和常量,因此类Bar
作为其单例类的一个实例,将作为所谓的“类”方法继承这一新功能。在Ruby中,模块和类只能有实例方法,因此“class”方法的创建实际上只是在类的单例类中创建一个实例方法,以这种方式继承
Bar.singleton_class.send( :include, Foo )
在这里,您可以看到include
和extend
的行为差异。要验证他们在类祖先方面的行为,您可以询问Bar
及其单例类的祖先,它将向您显示moduleBlah
是Bar
的直接父类,而moduleFoo
是单例类的直接父类
Bar.baz
# => 'baz'
Bar.magic
# => 'magic'
Bar.blah
# => NoMethodError
Bar.new.baz
# => NoMethodError
Bar.new.magic
# => NoMethodError
Bar.new.blah
# => 'blah'
从这些结果中,您可以看到包含如何模拟including类中的继承,以及扩展如何仅仅包含在singleton类中
Bar.baz
# => 'baz'
Bar.magic
# => 'magic'
Bar.blah
# => NoMethodError
Bar.new.baz
# => NoMethodError
Bar.new.magic
# => NoMethodError
Bar.new.blah
# => 'blah'
你可以试着看看我刚才得到的答案;他们出色地解释了include
和extend
功能的行为。
也帮助我理解了他们之间的差异。你说的内部差异是什么意思?如果您想要(并且需要)这种详细程度,您可以直接阅读源代码,我不需要实际的cpp实现。我正在阅读abt ruby对象模型。我确实包含了这个模块,我在上面的问题中指定了它。但是我找不到任何关于扩展模块的明确信息。我想从理论上了解它是如何实施的。迈克·李的回答是正确的。没有冒犯的意思,但这正是我在关于“包括”的问题中所说的。我想知道当我们“扩展”一个模块时会发生什么。他不是在说对象#include
?他说他知道当你包含时会发生什么,但他不清楚扩展。而且,这是正确的。特征类是关键。
Bar.singleton_class.send( :include, Foo )
Bar.baz
# => 'baz'
Bar.magic
# => 'magic'
Bar.blah
# => NoMethodError
Bar.new.baz
# => NoMethodError
Bar.new.magic
# => NoMethodError
Bar.new.blah
# => 'blah'
Bar.ancestors
# => [Bar, Blah, Object, Kernel, BasicObject]
Bar.singleton_class.ancestors
# => [Foo, Class, Module, Object, Kernel, BasicObject]