Dim*_*ets 10 ruby inheritance dynamic-dispatch object-model
首先,我明白这个问题在现实世界中没有应用,我只是好奇.
想象一下,我们有一个使用单例方法的类:
class Foo
def self.bar
end
end
Run Code Online (Sandbox Code Playgroud)
如果我们调用Foo.bar
它,它将首先在每个祖先的单例类中搜索一个方法Foo
,然后查看.class
方法及其祖先引用的类.我们可以确认,Foo.singleton_class.ancestors
返回:
[#<Class:Foo>, #<Class:Object>, #<Class:BasicObject>,
Class, Module, Object, Kernel, BasicObject]
Run Code Online (Sandbox Code Playgroud)
但是如果我们有一个嵌套的单例类会发生什么,比如:
class Foo
class << self
class << self
def bar
end
end
end
end
Run Code Online (Sandbox Code Playgroud)
如果我们打电话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]
Run Code Online (Sandbox Code Playgroud)
我不明白这个层次结构是如何组织的.
Kri*_*ján 18
大部分解释都是基于James Coglan的Ruby方法调度工作原理,这是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
Run Code Online (Sandbox Code Playgroud)
让我们从头开始构建.BasicObject
是一切的根源 - 如果你检查BasicObject.superclass
,你得到nil
.BasicObject
也是一个例子Class
.是的,这是循环的,并且代码中有一个特殊情况来处理它.什么时候,是一个孩子A
的实例,所以我们得到这个:B
A.singleton_class
B
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
Run Code Online (Sandbox Code Playgroud)
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>
Run Code Online (Sandbox Code Playgroud)
Kernel
是一个实例Module
.它是Module
我们唯一看到的实例,它的单例类没有出现在任何祖先链中,所以我不会超越它.
现在我们归结为Foo
,继承自Object
(虽然你不需要写< Object
).我们已经可以弄清楚Foo
它和它的单身类是什么了.
Class
^
|
BasicObject ~~~~~> #<Class:BasicObject>
^ ^
| Kernel |
| ^ |
| | |
+-----+----+ |
| |
Object ~~~~~~> #<Class:Object>
^ ^
| |
Foo ~~~~~~~~> #<Class:Foo>
Run Code Online (Sandbox Code Playgroud)
现在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>
Run Code Online (Sandbox Code Playgroud)
最后一步.每个实例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>>
Run Code Online (Sandbox Code Playgroud)
如果你从这个图中的任何节点开始并且从深度优先,从右到左遍历(并且停在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>]
Run Code Online (Sandbox Code Playgroud)
您也可以验证任何一个父母node.superclass
.
> Foo.singleton_class.singleton_class.superclass
=> #<Class:#<Class:Object>>
Run Code Online (Sandbox Code Playgroud)
您甚至可以验证对象标识是否一致,因此没有匿名类在整个地方弹出,彼此之间没有特定的关系.
> 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
Run Code Online (Sandbox Code Playgroud)
而且,简而言之,就是你如何狙击书呆子.
归档时间: |
|
查看次数: |
509 次 |
最近记录: |