这个解释的大部分是基于James Coglan 的How Ruby Method Dispatch Works 、 Ruby Hacking Guide的一小部分和源代码的一小部分。
首先总结一下,祖先是这样的:
+----------------+
| |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module> |
| ^ ^ |
| | | |
| Class ~~~~~~~~~~~~~~~> #<Class:Class> |
| ^ ^ |
| | | |
| BasicObject ~~~~~> #<Class:BasicObject> ~~> #<Class:#<Class:BasicObject>> |
| ^ ^ ^ |
| | Kernel | | |
| | ^ | | |
| | | | +-----------------------|----------------+
| +-----+----+ | | |
| | | v |
+-------> Object ~~~~~~> #<Class:Object> ~~~~~~~~> #<Class:#<Class:Object>>
^ ^ ^
| | |
Foo ~~~~~~~~> #<Class:Foo> ~~~~~~~~~~> #<Class:#<Class:Foo>>
---> Parent
~~~> Singleton class
让我们从头开始构建。BasicObject
是一切的根源——如果你检查BasicObject.superclass
,你就会得到nil
。BasicObject
也是 的一个实例Class
。是的,这是循环的,并且代码中有一个特殊情况来处理它。什么时候A
是 的一个实例B
,A.singleton_class
是 的一个孩子B
,所以我们得到这个:
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
Object
继承自BasicObject
。当A
继承自时B
,A
是 的子级B
并且A.singleton_class
是 的子级B.singleton_class
。Object
还包括Kernel
. 当A
include时B
,作为(在其自身之后,但在 之前)B
的第一个祖先插入。A
A
A.superclass
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject
^ ^
| Kernel |
| ^ |
| | |
+-----+----+ |
| |
Object ~~~~~~> #<Class:Object>
Kernel
是 的一个实例Module
。这是我们将看到的唯一实例Module
,它的单例类没有出现在任何祖先链中,所以我不会超越它。
现在我们开始讨论Foo
,它继承自Object
(尽管你不需要写< Object
)。我们已经可以弄清楚什么Foo
和它的单例类是子类。
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
^ ^
| Kernel |
| ^ |
| | |
+-----+----+ |
| |
Object ~~~~~~> #<Class:Object>
^ ^
| |
Foo ~~~~~~~~> #<Class:Foo>
现在Class
继承自Module
,并Module
继承自Object
,所以添加Module
和适当的单例类。因为Module < Object
和Object < BasicObject
,BasicObject.instance_of?(Class)
这是绘图变得有点时髦的地方。请记住,只要您击中 ,就停止向上移动BasicObject
。
+----------------+
| |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module> |
| ^ ^ |
| | | |
| Class ~~~~~~~~~~~~~~~> #<Class:Class> |
| ^ |
| | |
| BasicObject ~~~~~> #<Class:BasicObject> |
| ^ ^ |
| | Kernel | |
| | ^ | |
| | | | +----------------------------------------+
| +-----+----+ | |
| | | v
+-------> Object ~~~~~~> #<Class:Object>
^ ^
| |
Foo ~~~~~~~~> #<Class:Foo>
最后一步。的每个实例Class
都有一个singleton_class
(尽管在需要之前不会实例化它,否则您需要更多 RAM)。我们所有的单例类都是 的实例Class
,所以它们都有单例类。注意这句话:一个类的单例类的父类是该类的父类的单例类。我不知道是否有一种简洁的方式来说明就类型系统而言,Ruby 源代码几乎说它只是为了保持一致性而这样做。因此,当您请求 时Foo.singleton_class.singleton_class
,语言会愉快地满足您的要求并向上传播必要的双亲,最终导致:
+----------------+
| |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module> |
| ^ ^ |
| | | |
| Class ~~~~~~~~~~~~~~~> #<Class:Class> |
| ^ ^ |
| | | |
| BasicObject ~~~~~> #<Class:BasicObject> ~~> #<Class:#<Class:BasicObject>> |
| ^ ^ ^ |
| | Kernel | | |
| | ^ | | |
| | | | +-----------------------|----------------+
| +-----+----+ | | |
| | | v |
+-------> Object ~~~~~~> #<Class:Object> ~~~~~~~~> #<Class:#<Class:Object>>
^ ^ ^
| | |
Foo ~~~~~~~~> #<Class:Foo> ~~~~~~~~~~> #<Class:#<Class:Foo>>
如果您从该图中的任何节点开始并深度优先遍历,从右到左(并停在BasicObject
,您会得到节点的祖先链,就像我们想要的那样。而且,我们已经从一些基本公理构建了它,所以我们可能只是能够信任它。缺乏信任,有一些有趣的方法可以进一步验证结构。
尝试查看图中node.singleton_class.ancestors - node.ancestors
的任何节点。这为我们提供了单例类的祖先,而不是节点本身的祖先,从而消除了列表中一些令人困惑的冗余。
> Foo.singleton_class.singleton_class.ancestors - Foo.singleton_class.ancestors
=> [#<Class:#<Class:Foo>>, #<Class:#<Class:Object>>, #<Class:#<Class:BasicObject>>,
#<Class:Class>, #<Class:Module>]
您还可以使用 验证任何一位家长node.superclass
。
> Foo.singleton_class.singleton_class.superclass
=> #<Class:#<Class:Object>>
而且您甚至可以验证对象身份是否完全一致,因此不会到处出现匿名类,彼此之间没有特定关系。
> def ancestor_ids(ancestors)
> ancestors.map(&:object_id).zip(ancestors).map{|pair| pair.join("\t")}
> end
> puts ancestor_ids(Foo.ancestors)
70165241815140 Foo
70165216040500 Object
70165216040340 Kernel
70165216040540 BasicObject
> puts ancestor_ids(Foo.singleton_class.ancestors)
70165241815120 #<Class:Foo>
70165216039400 #<Class:Object>
70165216039380 #<Class:BasicObject>
70165216040420 Class
70165216040460 Module
70165216040500 Object # Same as Foo from here down
70165216040340 Kernel
70165216040540 BasicObject
> puts ancestor_ids(Foo.singleton_class.singleton_class.ancestors)
70165241980080 #<Class:#<Class:Foo>>
70165215986060 #<Class:#<Class:Object>>
70165215986040 #<Class:#<Class:BasicObject>>
70165216039440 #<Class:Class>
70165216039420 #<Class:Module>
70165216039400 #<Class:Object> # Same as Foo.singleton_class from here down
70165216039380 #<Class:BasicObject>
70165216040420 Class
70165216040460 Module
70165216040500 Object
70165216040340 Kernel
70165216040540 BasicObject
简而言之,这就是你狙击书呆子的方式。