当模块在Ruby中扩展时,内部会发生什么?

当模块在Ruby中扩展时,内部会发生什么?,ruby,Ruby,当一个模块包含在一个类中时,将创建一个匿名代理类并将其设置为MyClass的超类 Foo = Module.new class MyClass include Foo end 但是当模块被扩展时,内部会发生什么?Ruby如何处理这个问题 在Ruby中扩展模块时,内部会发生什么 当模块M包含在类C中时,匿名代理类⟦M′⟧(称为include类)时,其方法表指针指向M的方法表。(常数表和模块变量也是如此。)⟦M′⟧的超类设置为C的超类,C的超类设置为⟦M′⟧ 此外,如果M包括其他模块,则递归

当一个模块包含在一个类中时,将创建一个匿名代理类并将其设置为MyClass的超类

Foo = Module.new

class MyClass
  include Foo
end
但是当模块被扩展时,内部会发生什么?Ruby如何处理这个问题

在Ruby中扩展模块时,内部会发生什么

当模块
M
包含在类
C
中时,匿名代理类
⟦M′⟧(称为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
    及其单例类的祖先,它将向您显示module
    Blah
    Bar
    的直接父类,而module
    Foo
    是单例类的直接父类

    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]