2012-05-09 124 views
12

我知道ruby中的所有类都是元类Class的实例。而“常规”对象是这些类的实例(metaclass Class的实例)。但我一直想知道,我的意思是类是对象的根,类本身是类的实例(称为元类,因为它的实例是类)。我在一些博客中看到了一些覆盖类Class的方法newRuby元类困惑

因此,类表现为一个类,但其实例是类。所以看起来我们有一个圈,它看起来很喜欢class Class,它本身就是一个实例。

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

这里有一个交代不清的我举一个例子:

class Class 
    def new 
    #something 
    end 
end 

但关键字class意味着Class类的一个实例。那么这是如何工作的?

+4

'Class.class#=> Class' – Flexoid

+5

它一直都是乌龟! –

+0

另请参见[类/对象悖论混乱](http://stackoverflow.com/questions/7675774/the-class-object-paradox-confusion)。 –

回答

28

如何做好这项工作

简单:它没有。无论如何,不​​在Ruby中。

就像在其他大多数语言中一样,有一些核心实体被简单地假设存在。它们从天而降,变得空气稀薄,奇迹般地出现。

在Ruby中,其中的一些神奇的事情是:

  • Object没有一个超类,但你不能没有超定义一个类,隐含的直接超类总是Object。 [注意:可能有实现定义的超类Object,但最终会有一个没有超类的。]
  • ObjectClass一个实例,这是Object子类(这意味着间接ObjectObject自身的实例)
  • Class被的Module一个子类,其是Class
  • Class一个实例是Class的一个实例

这些事情都不能在Ruby中解释。

BasicObject,Object,ModuleClass都需要同时存在,因为它们具有循环依赖性。

仅仅因为这种关系不能用Ruby代码表达,并不意味着Ruby语言规范不能说它必须如此。实现者需要找出一种方法来实现这一点。毕竟,Ruby实现对程序员不具备的对象有一定的访问权限。

例如,Ruby实现可以先创建BasicObject,同时设置了superclass指针和class指针null

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

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

最后,它创建Class,其superclass指针设置为Module及其class指针null。现在

,我们可以覆盖BasicObject的,Object的,Module's和Classclass指针指向Class,我们就大功告成了。

这很容易从系统外部做,它看起来很奇怪。

然而,他们一旦确实存在,那么完全可以在纯Ruby中实现其大部分行为。您只需要这些类的准系统版本,这要感谢Ruby的开放类,您可以稍后添加任何缺少的功能。

在您的例子中,class Class不创建一个名为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 

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

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

+3

我想你的意思是“'BasicObject'的超类是'nil'',因为'Object'的超类是'BasicObject'。 –

+2

@AndrewMarshall:这是1.9的新功能。 1.8只有'Object'没有'BasicObject'。 –

+2

@HolgerJust没错,但1.8接近生命周期,除非提交者指定我假设最新版本的Ruby。 –

1

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

+0

为什么说这里与Parello使用“metaclass”这个词没有任何关系。他所谈论的是单身人士课程,或更通俗地讲,是特征课程。 – Chuck

2

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

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

+1

事实上,根据一般定义,Class可以被称为元类。但是我错误地将世界元类用于许多红宝石主义者的其他事情。但根据一般定义,这些元类是弱元类。如果我记得好的话,通常在ruby中称为元类的东西是持有类方法的单例。我已经阅读了几篇关于它的文章,说metaclass这个词被错误地使用了,并且他们在这一点上责怪rails团队。感谢大家。 – Perello

2

“twist”链接给出了一个meta-circularity。它是从根的本征类到Class类的内置超类链接。这可以通过

BasicObject.singleton_class.superclass == Class 

甲线索来表示对理解.class地图是看到此映射从eigenclass和超链接导出:对于对象xx.class处于x的超类链中的第一类eigenclass。这可以通过

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

其中eigenclasssingleton_class 一个“概念别名”(抗与立即值的问题)来表示,y.superclass(i)意味着yi个超类和n是最小的,使得x.eigenclass.superclass(n)是一个类。等效地,跳过x.eigenclass的超类链中的本征类(参见rb_class_real,其也揭示了在MRI中,即使superclass链接也通过跳过“ iclasses”而间接地实现了–)。 这导致每个类(以及每个特征类)的class始终是Class类。

图片由this diagram提供。

元类混乱有2个主要来源:

  • Smalltalk的。 Smalltalk-80对象模型包含由Ruby对象模型纠正的概念不一致。另外,Smalltalk文献在术语中使用辩证法,遗憾的是在Ruby文献中尚未得到充分的补救。

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