我的理解是,当一个模块被包含在一个类中时,模块的副本就会被创建并放在包含类和它的超类之间。 让我引用Pat Shaughnessy撰写的 Ruby Under Microscope 。假设您有以下内容:
module Professor
end
class Mathematician < Person
include Professor
end
当我们运行上面的代码时,Ruby会为
RClass
模块创建Professor
结构的副本,并将其用作Mathematician
的新超类。 Ruby的C源代码将该模块的副本称为包含的类。新Professor
副本的超类设置为Mathematician
的原始超类,它保留了超类或祖先链。
是否可以获得对包含的类的引用?例如,我想获得对Kernel
类中包含的Object
模块的引用。
答案 0 :(得分:3)
我的理解是,当一个模块被包含在一个类中时,a 模块的副本被制作并放在包含类和它之间 超类。
从Ruby的角度来看,没有复制。引用被添加到祖先,这就是它。
您问题中描述的行为(摘自"Ruby under a microscope")可能与CRuby有关。在内部,Ruby模块保存为修改后的RClass
,并在包含模块时生成副本。例如,在Rubinius中似乎并非如此。我也不认为可以访问复制的内部RClass
来引用Ruby中包含的模块。
您可以通过以下方式检查Ruby行为:
module M
def copy_or_reference?
puts "copy!"
end
end
class A
include M
end
class B
include M
end
m2 = A.included_modules.first
m2.send(:define_method, :copy_or_reference?) { puts "reference!" }
B.new.copy_or_reference?
#=> reference!
我们从M
的祖先中提取A
模块。我们在此祖先模块中重新定义copy_or_reference?
方法。如果它是原始M
模块的副本,M#copy_or_reference?
,从B
实例调用,仍会返回"copy!"
。
要获取包含的模块,您还可以使用:
A.ancestors.grep_v(Class)
在Ruby 2.3+或
中A.ancestors.reject{ |o| o.is_a?(Class) }
旧版本。
如果您想了解更多信息,可以尝试ping @JörgWMittag。
答案 1 :(得分:1)
让我们看一下样本:
module Bar
end
class Foo
include Bar
end
p Foo.ancestors
p Foo.included_modules
这将打印
[Foo, Bar, Object, Kernel, BasicObject]
[Bar, Kernel]
Object
和BasicObject
位于祖先层次结构中,因为即使没有指定它,Foo
也会延伸Object
(和Object
扩展&#39; BasicObject& #39;,至少从引入BasicObject
的Ruby 1.9+开始。)
Bar
和Kernel
包含模块,因为Foo
直接包含Bar
,Object
包含Kernel
。
但Module
未被复制。在查找方法时,它只是被引用和使用。
您可以在此处找到更多详细信息:http://ruby-doc.com/docs/ProgrammingRuby/html/tut_modules.html