11

首先,我知道这个问题在现实世界中没有应用,我只是好奇。

想象一下,我们有一个带有单例方法的类:

class Foo
    def self.bar
    end
end

如果我们调用Foo.bar,它将首先在 的每个祖先的单例类中搜索一个方法Foo,然后在.class方法及其祖先引用的类中查找。我们可以用 来确认Foo.singleton_class.ancestors,它返回:

[#<Class:Foo>, #<Class:Object>, #<Class:BasicObject>,
 Class, Module, Object, Kernel, BasicObject]

但是如果我们有一个嵌套的单例类会发生什么,比如:

class Foo
  class << self
    class << self
      def bar
      end
    end
  end
end

如果我们调用Foo.singleton_class.singleton_class.ancestors,它会返回:

[#<Class:#<Class:Foo>>, #<Class:#<Class:Object>>,
 #<Class:#<Class:BasicObject>>, #<Class:Class>, #<Class:Module>,
 #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

我不明白这个层次结构是如何组织的。

4

2 回答 2

19

这个解释的大部分是基于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,你就会得到nilBasicObject也是 的一个实例Class。是的,这是循环的,并且代码中有一个特殊情况来处理它。什么时候A是 的一个实例BA.singleton_class是 的一个孩子B,所以我们得到这个:

                           Class
                             ^
                             |
BasicObject ~~~~~> #<Class:BasicObject>

Object继承自BasicObject。当A继承自时BA是 的子级B并且A.singleton_class是 的子级B.singleton_classObject还包括Kernel. 当Ainclude时B,作为(在其自身之后,但在 之前)B的第一个祖先插入。AAA.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 < ObjectObject < BasicObjectBasicObject.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

简而言之,这就是你狙击书呆子的方式。

于 2015-08-07T05:18:31.910 回答
3

#<Class:Foo>是给定类的特征/匿名类Foo。如果此特征/匿名类也已扩展,则将创建另一个特征类 - 因此表示为#<Class:#<Class:Foo>>

本征类的Object父类是类的本征类,其父类是 的本征类BasicObject。同理,另一个本征类的本征类的父类是该类的本征类的本征类Object,以此类推。

下面的代码加上这个解释提供了更多的见解

p Foo.class
p Foo.class.ancestors
puts "-----------------"
p Foo.singleton_class
p Foo.singleton_class.ancestors
puts "-----------------"
p Foo.singleton_class.singleton_class
p Foo.singleton_class.singleton_class.ancestors

哪个输出

Class
[Class, Module, Object, Kernel, BasicObject]
-----------------
#<Class:Foo>
[#<Class:Foo>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
-----------------
#<Class:#<Class:Foo>>
[#<Class:#<Class:Foo>>, #<Class:#<Class:Object>>, #<Class:#<Class:BasicObject>>, #<Class:Class>, #<Class:Module>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

如上所示的特征类层次结构将重复到任意数量的级别。例如:

p Foo.singleton_class.singleton_class.singleton_class.singleton_class.singleton_class
puts "-----------------"
p Foo.singleton_class.singleton_class.singleton_class.singleton_class.singleton_class.ancestors

以上代码输出

#<Class:#<Class:#<Class:#<Class:#<Class:Foo>>>>>
-----------------
[#<Class:#<Class:#<Class:#<Class:#<Class:Foo>>>>>, #<Class:#<Class:#<Class:#<Class:#<Class:Object>>>>>, #<Class:#<Class:#<Class:#<Class:#<Class:BasicObject>>>>>, #<Class:#<Class:#<Class:#<Class:Class>>>>, #<Class:#<Class:#<Class:#<Class:Module>>>>, #<Class:#<Class:#<Class:#<Class:Object>>>>, #<Class:#<Class:#<Class:#<Class:BasicObject>>>>, #<Class:#<Class:#<Class:Class>>>, #<Class:#<Class:#<Class:Module>>>, #<Class:#<Class:#<Class:Object>>>, #<Class:#<Class:#<Class:BasicObject>>>, #<Class:#<Class:Class>>, #<Class:#<Class:Module>>, #<Class:#<Class:Object>>, #<Class:#<Class:BasicObject>>, #<Class:Class>, #<Class:Module>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
于 2015-08-06T18:49:10.113 回答