Ruby元类混淆
我知道ruby中的所有类都是元类Class的实例。 而“常规”对象是这些类的实例(元类Class的实例)。
但我一直在想,我的意思是类是对象的根,类本身就是Class的实例(称为元类,因为它的实例是类)。 我在一些博客中看到了类Class的一些new
方法。
所以Class表现为一个类,但它的实例是类。 所以看起来我们有一个圆圈,它看起来像类Class是它自己的一个实例。
我在这里显然错过了一点。 class级的起源是什么?
这是一个令我困惑的例子:
class Class def new #something end end
但是关键字class
意味着类Class的实例。 那怎么办呢?
这是怎么回事
容易:它没有。 反正不是在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
指针及其class
指针设置为null
。
然后,它创建Object
,将其superclass
指针设置为BasicObject
,将其superclass
指针设置为null
。
接下来,它创建Module
,将其superclass
指针设置为Object
,将其superclass
指针设置为null
。
最后,它创建了Class
,将其superclass
指针设置为Module
,将其superclass
指针设置为null
。
现在,我们可以覆盖BasicObject
的, Object
, Module
和Class
的class
指针,指向Class
,我们就完成了。
这很容易从系统外部进行,它从内部看起来很奇怪。
但是,一旦它们确实存在,完全可以在纯Ruby中实现它们的大多数行为。 您只需要这些类的非常准确的版本,多亏了Ruby的开放类,您可以在以后添加任何缺少的function。
在您的示例中, class Class
不创建名为Class
的新类,它重新打开现有的类Class
,它是由运行时环境提供给我们的。
因此,完全有可能在纯Ruby中解释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
[注意:实际上, initialize
是私有的,因此您需要使用obj.send(:initialize, *args, &block)
来规避访问限制。
BTW: Class#allocate
是另一个神奇的东西。 它在Ruby的对象空间中分配一个新的空对象,这是Ruby中无法完成的。 因此, Class#allocate
也必须由运行时系统提供。
是的,Class是它自己的一个实例。 它是Module的子类,也是类的实例,Module是Object的子类,它也是Class的一个实例。 它确实非常循环 – 但这是核心语言的一部分,而不是库中的东西。 当我们编写Ruby代码时,Ruby运行时本身对你或我没有相同的限制。
不过,我从来没有听过“metaclass”这个词用来谈论Class。 它根本没有在Ruby中使用太多,但是当它出现时,它通常是正式称为“对象的单例类”的同义词,这是一个比Object-Module-Class三角形更令人困惑的话题。
“扭曲”链接给出了一个元循环。 它是从根的本征Class
到Class
类的内置超类链接。 这可以表达为
BasicObject.singleton_class.superclass == Class
理解.class
映射的线索是看到这个映射是从本征类和超类链接派生的:对于一个对象x
, x.class
是x
x.class
类的超类链中的第一个类。 这可以表达为
x.class == x.eigenclass.superclass(n)
其中eigenclass
是singleton_class
的“概念别名”(对具有立即值的问题有抵抗), y.superclass(i)
表示第i
个超类y
和n
最小,因此x.eigenclass.superclass(n)
是一个类。 同样,跳过了x.eigenclass的超类链中的特征类(参见rb_class_real ,它也揭示了在MRI中,甚至superclass
链接也是间接实现的 – 它们是通过跳过“ iclasses ”而产生的)。 这导致每个类(以及每个本征Class
类始终是Class
类。
该图提供了一张图片。
元类混淆有两个主要来源:
-
Smalltalk 。 Smalltalk-80对象模型包含由Ruby对象模型纠正的概念不一致性。 此外,Smalltalk文献在术语中使用了辩证法,遗憾的是在Ruby文献中没有对其进行充分的补救。
-
元类的定义 。 目前,该定义指出元类是类的类 。 然而,对于所谓的“ 隐式元类 ”(Ruby和Smalltalk-80的情况),更合适的定义将是类的元对象 。
虽然它有点过时, _Why的这篇文章可能有助于理解行为。 您可以在Paolo Perrotta的Metaprogramming Ruby中找到更深入的主题。