想象一下,我们有一个有单一方法的课程:
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]
我不明白这个层次结构是如何组织的.
解决方法
要从总结开始,祖先看起来像这样:
+----------------+ | | +--------------------------- 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 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.