参考随附的“模块”

时间:2017-07-13 01:33:27

标签: ruby

我的理解是,当一个模块被包含在一个类中时,模块的副本就会被创建并放在包含类和它的超类之间。 让我引用Pat Shaughnessy撰写的 Ruby Under Microscope 。假设您有以下内容:

module Professor
end
class Mathematician < Person
   include Professor
end
  

当我们运行上面的代码时,Ruby会为RClass模块创建Professor结构的副本,并将其用作Mathematician的新超类。 Ruby的C源代码将该模块的副本称为包含的类。新Professor副本的超类设置为Mathematician的原始超类,它保留了超类或祖先链。

是否可以获得对包含的类的引用?例如,我想获得对Kernel类中包含的Object模块的引用。

2 个答案:

答案 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]

ObjectBasicObject位于祖先层次结构中,因为即使没有指定它,Foo也会延伸Object(和Object扩展&#39; BasicObject& #39;,至少从引入BasicObject的Ruby 1.9+开始。)

BarKernel包含模块,因为Foo直接包含BarObject包含Kernel

Module未被复制。在查找方法时,它只是被引用和使用。

您可以在此处找到更多详细信息:http://ruby-doc.com/docs/ProgrammingRuby/html/tut_modules.html