首先,我知道这个问题在现实世界中没有应用,我只是好奇。
想象一下,我们有一个使用单例方法的类:
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]
我不明白这种层次结构是如何组织的。
答案 0 :(得分:18)
这些解释大部分基于詹姆斯·科格兰的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
,则会获得nil
。 BasicObject
也是Class
的一个实例。是的,这是循环的,并且有special case in the code来处理它。当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
包含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 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
处停留),您将获得节点的祖先链,就像我们想要的那样。而且,我们和从一些基本公理中建立了它,所以我们可能只能信任它。缺乏信任,有一些有趣的方法可以进一步验证结构。
尝试查看图表中任何节点的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
简而言之,就是snipe a nerd。
答案 1 :(得分:3)
#<Class:Foo>
是给定类Foo
的特征/匿名类。如果此特征/匿名类也已被扩展,则将创建另一个特征类 - 因此表示为#<Class:#<Class:Foo>>
特征类的父类是Object
类的特征类,其父类是BasicObject
的特征类。类似地,另一个特征类的特征类的父类是Object
类的特征类的特征类,依此类推。
以下代码耦合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]
如上所示的特征类层次结构将重复到任意数量的级别。 例如:
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]