Ruby元类混淆

时间:2012-05-09 22:33:03

标签: ruby metaclass

我知道ruby中的所有类都是元类Class的实例。而“常规”对象是这些类的实例(元类Class的实例)。

但我一直在想,我的意思是类是对象的根,类本身就是Class的实例(称为元类,因为它的实例是类)。我在一些博客中看到了类Class的方法new的重写。

所以Class表现为类,但它的实例是类。所以看起来我们有一个圆圈,它看起来像类Class是它自己的一个实例。

我显然在这里错过了一点。班级的起源是什么?

这是一个令我困惑的例子:

class Class
  def new
    #something
  end
end

但关键字class意味着类Class的实例。那怎么办呢?

4 个答案:

答案 0 :(得分:29)

  

这是如何运作的

容易:事实并非如此。反正不是在Ruby中。

就像大多数其他语言一样,有一些核心实体被假设存在。它们从天而降,凭空出现,神奇地出现。

在Ruby中,其中一些神奇的东西是:

  • Object没有超类,但是你不能定义没有超类的类,隐式直接超类总是Object。 [注意:可能存在实现定义的Object超类,但最终会有一个没有超类的超类。]
  • ObjectClass的一个实例,它是Object的子类(这意味着间接ObjectObject本身的实例)< / LI>
  • ClassModule的子类,是Class
  • 的一个实例
  • ClassClass
  • 的一个实例

这些都不能用Ruby解释。

BasicObjectObjectModuleClass都需要同时存在,因为它们具有循环依赖关系。

仅仅因为这种关系不能用Ruby代码表示,并不意味着Ruby语言规范不能说它必须如此。由实现者决定如何做到这一点。毕竟,Ruby实现具有对程序员所没有的对象的访问级别。

例如,Ruby实现可以首先创建BasicObject,将其superclass指针及其class指针设置为null

然后,它会创建Object,将superclass指针设置为BasicObject,将class指针设置为null

接下来,它会创建Module,将superclass指针设置为Object,将class指针设置为null

最后,它会创建Class,将superclass指针设置为Module,将class指针设置为null

现在,我们可以覆盖BasicObjectObjectModuleClass的{​​{1}}指针,指向{ {1}},我们已经完成了。

这很容易从系统外部进行,从内部看起来很奇怪。

然而,一旦他们,就完全有可能在纯Ruby中实现他们的大多数行为。您只需要这些类的非常准确的版本,感谢Ruby的开放类,您可以在以后添加任何缺少的功能。

在您的示例中,class未创建名为Class的新类,而是重新打开现有class Class,该类已提供给我们由运行时环境。

因此,完全有可能在普通Ruby中解释Class的默认行为:

Class

[注意:实际上,Class#new是私有的,因此您需要使用class Class def new(*args, &block) obj = allocate # another magic thing that cannot be explained in Ruby obj.initialize(*args, &block) return obj end end 来规避访问限制。]

BTW:initialize是另一个神奇的东西。它在Ruby的对象空间中分配一个新的空对象,这是Ruby无法完成的。因此,obj.send(:initialize, *args, &block)也必须由运行时系统提供。

答案 1 :(得分:2)

是的,Class是它自己的一个实例。它是Module的子类,它也是类的实例,Module是Object的子类,它也是Class的一个实例。它确实非常循环 - 但这是核心语言的一部分,而不是库中的东西。当我们编写Ruby代码时,Ruby运行时本身对你或我没有相同的限制。

我从来没有听过“metaclass”这个词用来谈论Class。它根本没有在Ruby中使用太多,但是当它出现时,它通常是官方称为“对象的单例类”的同义词,这是一个比Object-Module-Class三角形更令人困惑的话题。

答案 2 :(得分:2)

“扭曲”链接给出了一个元循环。它是从根的本征类到Class类的内置超类链接。这可以用

表示
BasicObject.singleton_class.superclass == Class

了解.class地图的一个线索是看到这个地图是从特征类和超类链接派生的:对于一个对象xx.class是超类链中的第一个类。 x的本征类。这可以用

表示
x.class == x.eigenclass.superclass(n)

其中eigenclasssingleton_class的“概念别名” (对具有直接值的问题有抵抗力),y.superclass(i)表示i - yn的超类最小,因此x.eigenclass.superclass(n)是一个类。同样地,跳过x.eigenclass的超类链中的特征类(参见rb_class_real,其中还揭示了在MRI中,甚至superclass链接是间接实现的 - 它们通过跳过“ iclasses < / i>的“)。 这导致每个类(以及每个本征类)的class始终是Class类。

图片由this diagram提供。

元类混淆有两个主要来源:

  • 的Smalltalk 的。 Smalltalk-80对象模型包含由Ruby对象模型纠正的概念不一致性。此外,Smalltalk文献在术语中使用了辩证法,遗憾的是,在Ruby文献中没有对其进行充分的补救。

  • 元类的定义。目前,该定义指出元类是类的类。但是,对于所谓的“隐式元类”(Ruby和Smalltalk-80的情况),更合适的定义将是类的元对象

答案 3 :(得分:1)

虽然它有点过时,this article by _why可能有助于理解行为。您可以在Paolo Perrotta的Metaprogramming Ruby中找到更深入的主题。