嵌套单例 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
,你会得到 nil
。 BasicObject
也是 Class
的一个实例。是的,这是循环的,有一个 special case in the code 来处理它。当 A
是 B
的实例时,A.singleton_class
是 B
的 child,所以我们得到:
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
Object
继承自 BasicObject
。当 A
继承自 B
时,A
是 B
的 child 而 A.singleton_class
是 [=35= 的 child ]. Object
还包括 Kernel
。当 A
包含 B
时,B
作为 A
的第一个祖先插入(在 A
本身之后,但在 A.superclass
之前)。
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject
^ ^
| Kernel |
| ^ |
| | |
+-----+----+ |
| |
Object ~~~~~~> #<Class:Object>
Kernel
是 Module
的实例。这是我们将看到的 Module
的唯一实例,它的单例 class 没有出现在任何祖先链中,所以我不会超越它。
现在我们开始 Foo
,它继承自 Object
(尽管您不需要写 < Object
)。我们已经可以搞清楚Foo
和它的单例class是children的
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
^ ^
| Kernel |
| ^ |
| | |
+-----+----+ |
| |
Object ~~~~~~> #<Class:Object>
^ ^
| |
Foo ~~~~~~~~> #<Class:Foo>
现在Class
继承自Module
,Module
继承自Object
,所以添加Module
和合适的单例classes .因为 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)。我们所有的单例 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.
首先,我知道这个问题在现实世界中没有应用,我只是好奇。
假设我们有一个 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
,你会得到 nil
。 BasicObject
也是 Class
的一个实例。是的,这是循环的,有一个 special case in the code 来处理它。当 A
是 B
的实例时,A.singleton_class
是 B
的 child,所以我们得到:
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
Object
继承自 BasicObject
。当 A
继承自 B
时,A
是 B
的 child 而 A.singleton_class
是 [=35= 的 child ]. Object
还包括 Kernel
。当 A
包含 B
时,B
作为 A
的第一个祖先插入(在 A
本身之后,但在 A.superclass
之前)。
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject
^ ^
| Kernel |
| ^ |
| | |
+-----+----+ |
| |
Object ~~~~~~> #<Class:Object>
Kernel
是 Module
的实例。这是我们将看到的 Module
的唯一实例,它的单例 class 没有出现在任何祖先链中,所以我不会超越它。
现在我们开始 Foo
,它继承自 Object
(尽管您不需要写 < Object
)。我们已经可以搞清楚Foo
和它的单例class是children的
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
^ ^
| Kernel |
| ^ |
| | |
+-----+----+ |
| |
Object ~~~~~~> #<Class:Object>
^ ^
| |
Foo ~~~~~~~~> #<Class:Foo>
现在Class
继承自Module
,Module
继承自Object
,所以添加Module
和合适的单例classes .因为 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)。我们所有的单例 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.