嵌套单例 class 方法查找

Nested singleton class method lookup

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

假设我们有一个 class 和单例方法:

class Foo
    def self.bar
    end
end

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

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

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

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

如果我们调用Foo.singleton_class.singleton_class.ancestors,它returns:

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

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

#<Class:Foo> 是给定 class Foo 的 eigen/anonymous class。如果此 eigen/anonymous class 也已扩展,则会创建另一个本征 class - 因此表示为 #<Class:#<Class:Foo>>

特征值 class 的父项是 Object class 的特征值 class,其父项是 BasicObject 的特征值 class。类似地,另一个特征 class 的特征 class 的父元素是 Object class 的特征 class 的特征 class,等等上。

结合下面的代码 with this explanation 提供更多见解

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]

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

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]

大部分解释基于How Ruby Method Dispatch Works by James Coglan, a little of the Ruby Hacking Guide, and just a smidge of source

首先总结一下,祖先看起来像这样:

                                                           +----------------+
                                                           |                |
+--------------------------- 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 的一个实例。是的,这是循环的,有一个 special case in the code 来处理它。当 AB 的实例时,A.singleton_classB 的 child,所以我们得到:

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

Object 继承自 BasicObject。当 A 继承自 B 时,AB 的 child 而 A.singleton_class 是 [=35= 的 child ]. Object 还包括 Kernel。当 A 包含 B 时,B 作为 A 的第一个祖先插入(在 A 本身之后,但在 A.superclass 之前)。

                           Class
                             ^
                             |
BasicObject ~~~~~> #<Class:BasicObject
    ^                        ^
    |        Kernel          |
    |          ^             |
    |          |             |
    +-----+----+             |
          |                  |
        Object ~~~~~~> #<Class:Object>

KernelModule 的实例。这是我们将看到的 Module 的唯一实例,它的单例 class 没有出现在任何祖先链中,所以我不会超越它。

现在我们开始 Foo,它继承自 Object(尽管您不需要写 < Object)。我们已经可以搞清楚Foo和它的单例class是children的

                           Class
                             ^
                             |
BasicObject ~~~~~> #<Class:BasicObject>
    ^                        ^
    |        Kernel          |
    |          ^             |
    |          |             |
    +-----+----+             |
          |                  |
        Object ~~~~~~> #<Class:Object>
          ^                  ^
          |                  |
         Foo ~~~~~~~~> #<Class:Foo>

现在Class继承自ModuleModule继承自Object,所以添加Module和合适的单例classes .因为 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)。我们所有的单例 classes 都是 Class 的实例,所以他们有单例 classes。注意这句话:A class's singleton class's parent is the class's parent's singleton class.我不知道是否有一种简洁的方式来说明就类型系统而言,Ruby source 几乎说它只是为了在任何情况下保持一致性。因此,当您请求 Foo.singleton_class.singleton_class 时,语言很乐意满足您的要求并向上传播必要的 parent,最终导致:

                                                           +----------------+
                                                           |                |
+--------------------------- 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>>

如果你从这个图中的任何一个节点开始,从右到左遍历 depth-first(并在 BasicObject 处停止),你就会得到该节点的祖先链,就像我们想要的那样。而且,我们它是根据一些基本公理构建的,所以我们可能只能信任它。缺乏信任,有几种有趣的方法可以进一步验证结构。

尝试查看 node.singleton_class.ancestors - node.ancestors 图中的任何节点。这为我们提供了单例的祖先 class 而不是节点本身的祖先,从而消除了列表中一些令人困惑的冗余。

> 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验证任何一个parent。

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

而且您甚至可以验证 object 身份完全一致,因此不会出现彼此之间没有特定关系的匿名 classes。

> 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

简而言之,这就是您 snipe a nerd.