5

这主要是一个“学术”,但在这里:

根据this Ruby eigenclass diagram(稍作编辑):

可能错误的 Ruby 特征类图

BasicObject.singleton_class.singleton_class.superclassClass

但是,在 Ruby 解释器(Ruby v2.5.1)上运行它,结果是BasicObject.singleton_class.singleton_class.superclassis#<Class:Class>而不是Class. 因此,图表是在说谎还是我错过了什么?

该图来自我在 Freenode 的 Ruby IRC 聊天的一位用户。然而,它被许多其他用户多次引用,并被视为 Ruby 对象模型圣经。

4

1 回答 1

2

Ruby 解释器的行为非常合理,因为:

  • 当一个Child类扩展 aParent时,Ruby 设置它以便单例类也#<Class:Child>扩展#<Class:Parent>;和
  • BasicObject.singleton_class是 的子类Class,所以BasicObject.singleton_class.singleton_class将是 的子类#<Class:Class>

验证相等性:

BasicObject.singleton_class.singleton_class.superclass.equal?(Class.singleton_class)
#=> true

这就引出了下一个问题——为什么首先要#<Class:BaseObject>扩展Class?按照上面的规则,因为BaseObject没有超类——也就是说,BaseObject.superclassnil——合乎逻辑的事情是它的单例类也没有超类。

答案是,当涉及到单例类时,#<Class:BaseObject>扩展确保了继承层次结构的一致性。Class以这个 Ruby 对象为例:

obj = "a string"

这是一个公认的概念,我们可以将其视为其自己的单例类的(唯一)实例,而不是obj简单的实例,而单例类又是 的子类。那是:StringString

obj.class.equal?(obj.singleton_class.superclass)
#=> true

这似乎也适用于类实例是合乎逻辑的。但它没有,因为它与上面提到的规则相矛盾,其中一个类的单例类的超Child类是其类的单例Parent类。

class Foo; end

Foo.class
#=> Class

Foo.singleton_class.superclass
#=> #<Class:Object>      <-- not equal to Class!

# because:
Foo.superclass
#=> Object

但是可以通过放置Class在单例类继承层次结构的顶部来解决这个矛盾:

Foo.singleton_class.superclass
#=> #<Class:Object>

Foo.singleton_class.superclass.superclass
#=> #<Class:BasicObject>

Foo.singleton_class.superclass.superclass.superclass
#=> Class

这样,即使Foo.singleton_class.superclass不等于Foo.class,通过沿着继承链向上走,它最终也会到达那里......

于 2018-08-05T22:42:42.417 回答