ruby – 嵌套单例类方法查找

前端之家收集整理的这篇文章主要介绍了ruby – 嵌套单例类方法查找前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
首先,我明白这个问题在现实世界中没有应用,我只是好奇.

想象一下,我们有一个有单一方法的课程:

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>,BasicObject]

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

解决方法

这个解释大部分是基于 How Ruby Method Dispatch Works的詹姆斯·科格兰,Ruby Hacking Guide的一点,只是一个 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,您将获得零. BasicObject也是Class的一个实例.是的,这是通知,有一个special case in the code处理它.当A是B的一个实例时,A.singleton_class是B的孩子,所以我们得到:

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

Object从BasicObject继承.当A从B继承时,A是B的子节点,而Assingleton_class是B.singleton_class的子节点.对象也包括内核.当A包含B时,B插入作为A的第一个祖先(在A本身之后,但在A.superclass之前).

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

内核是Module的一个实例.这是我们将要看到的Module的唯一实例,它的单例类不会出现在任何祖先链中,所以我不会超出它.

现在我们来到Foo,它继承自Object(虽然你不需要写< Object).我们已经可以弄清楚什么是Foo及其单身阶级的孩子.

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

现在Class继承自Module,Module从Object继承,所以添加Module和适当的singleton类.因为模块&对象和对象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 source几乎都说它只是在任何情况下一致.所以,当你要求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开始,并且在BasicObject中停止),就可以像我们想要的那样获得节点的祖先链,而且我们已经从一些基本的公理我们可能只能信任它,缺乏信任,有一些有趣的方法可以进一步验证结构.

尝试查看图中任何节点的node.singleton_class.ancestors – node.ancestors.这给了我们单人类的祖先,不是节点本身的祖先,它消除了列表中的一些混乱的冗余.

> Foo.singleton_class.singleton_class.ancestors - Foo.singleton_class.ancestors
 => [#<Class:#<Class:Foo>>,#<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
701652160@R_502_449@40  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
701652160@R_502_449@40  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
701652160@R_502_449@40  Kernel
70165216040540  BasicObject

而且,简而言之,你是如何snipe a nerd.

猜你在找的Ruby相关文章