14

我知道 ruby​​ 中的所有类都是元类类的实例。并且那个“常规”对象是这些类的实例(元类类的实例)。

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

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

我显然在这里遗漏了一点。类Class的由来是什么?

这是一个让我感到困惑的例子:

class Class
  def new
    #something
  end
end

但是关键字class暗示了类Class的一个实例。那么这是如何工作的呢?

4

4 回答 4

34

这是怎么工作的

容易:它没有。无论如何,不​​在 Ruby 中。

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

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

  • Object没有超类,但不能定义没有超类的类,隐式直接超类总是Object. [注意:可能存在实现定义的超类Object,但最终会有一个没有超类。]
  • Object是 的一个实例Class,它是 的子类Object(这意味着间接地Object是它自己的一个实例Object
  • Class是 的子类Module,是 的实例Class
  • Class是一个实例Class

这些东西都不能用 Ruby 解释。

BasicObject, Object,Module并且Class都需要同时出现,因为它们具有循环依赖关系。

仅仅因为这种关系不能用 Ruby 代码表达,并不意味着 Ruby 语言规范不能说它必须如此。由实现者来想办法做到这一点。毕竟,Ruby 实现对您作为程序员所没有的对象具有一定的访问权限。

例如,Ruby 实现可以首先创建BasicObject,将其superclass指针和指针都设置classnull

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

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

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

现在,我们可以覆盖BasicObject's、Object's、Module's 和Class'class指向 的指针Class,我们就完成了。

这从系统外部很容易做到,只是从内部看起来很奇怪。

但是,一旦它们确实存在,就完全有可能在纯 Ruby 中实现它们的大部分行为。您只需要这些类的准系统版本,多亏了 Ruby 的开放类,您可以在以后添加任何缺少的功能。

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

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

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

[注:实际上initialize是私有的,所以你需要使用它obj.send(:initialize, *args, &block)来规避访问限制。]

顺便说一句:Class#allocate是另一种神奇的东西。它在 Ruby 的对象空间中分配一个新的空对象,这是 Ruby 无法做到的。因此,Class#allocate运行时系统也必须提供一些东西。

于 2012-05-10T00:30:14.173 回答
4

“扭曲”链接给出了元循环。它是从根的特征类到类的内置超类链接Class。这可以表示为

BasicObject.singleton_class.superclass == Class

理解该映射的一个线索.class是将该映射视为从 eigenclass 和 superclass 链接派生的:对于 object xx.class是 eigenclass 的超类链中x的第一个类。这可以表示为

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

其中eigenclasssingleton_class (抵抗立即值问题)的“概念别名”,y.superclass(i)表示i第一个超类,y并且n是最小x.eigenclass.superclass(n)的一个类。等价地,x.eigenclass跳过超类链中的特征类(参见rb_class_real,它还揭示了在 MRI 中,甚至superclass链接也是间接实现的——它们是通过跳过“ iclasses ”而产生的)。这导致class每个类(以及每个特征类)的 始终是Class类。

这张图提供了一张图片。

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

  • 小话。Smalltalk-80 对象模型包含由 Ruby 对象模型纠正的概念上的不一致。此外,Smalltalk 文献在术语中使用辩证法,不幸的是,Ruby 文献中没有充分纠正这一点。

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

于 2012-05-11T19:11:56.323 回答
3

是的,Class 是它自己的一个实例。它是Module的子类,也是类的实例,Module是Object的子类,Object也是Class的实例。它确实是循环的——但这是核心语言的一部分,而不是库中的东西。Ruby 运行时本身并没有你或我在编写 Ruby 代码时所做的限制。

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

于 2012-05-10T00:29:56.500 回答
2

虽然它有点过时,但_why 的这篇文章可能有助于理解这种行为。您可以在 Paolo Perrotta 的Metaprogramming Ruby中找到对该主题的更深入了解。

于 2012-05-10T00:10:13.703 回答