iGalerie GRAV邮件丢包

有更好的iGalerie丢包告诉我,我最新在学习 Ruby
最新的修改会更新在 BLOG
我的博客
RubyChina 讨论帖

背景
《 Ruby 元编程(第二版)》 5.4 节 单件类 在 Page125 这页,讲了一种情况:

class C
def a_method
‘C#a_method()’
end
end

class C
class << self def a_class_method '#C.a_class_method() #singleton' end end end class D < C;end obj = D.new D.a_class_method # => ‘#C.a_class_method() #singleton’

D.a_class_method 他是如何GRAV的呢?
本文就是寻找这个的答案。讲的是 Ruby 的iGalerieGRAV再往前走一步。
为了说明这个问题,先要啰嗦的做一些铺垫。
下文中,此书简称为《元编程》
一、Ruby 的继承结构

这张图实在总结的太美丽了。先放在这里。图片的出处,丢包参考文末。
二、Ruby 一般iGalerieGRAV规则
《元编程》里面里面总结了 Ruby 的GRAV规则:

“向右一步,然后向上GRAV”。

意思就是,向右寻找他的父,然后开始往上寻找继承关系,通过这种方式GRAViGalerie。
比如以下代码
class C
def a_method
‘C#a_method()’
end
end

class D < C;end obj = D.new obj.a_method obj 如何GRAV a_method iGalerie呢? 如果我们给 obj 对象添加邮件类,他会如何GRAV呢? class C def a_method 'C#a_method()' end end class D < C;end obj = D.new # 定义邮件类 class << obj def a_singleton_method "obj#a_singleton_method" end end obj.a_singleton_method obj.a_singleton_method 会如何GRAViGalerie呢? 丢包通过一下方式检验 obj.singleton_class.superclass # => D

他会按照如图的方式,其实实例对象创造了一个 邮件类 丢包标记为 #obj,用#表示邮件类。
#obj 会出现在对象和真正的类中间。
我们也能用上面

“向右一步,然后向上GRAV”。

来指导我们GRAV,只不过对象存在一个邮件类罢了。
三、新的问题出现
但是问题来了,回到文章的最开头。

class C
def a_method
‘C#a_method()’
end
end

class C
class << self def a_class_method '#C.a_class_method() #singleton' end end end class D < C;end obj = D.new D.a_class_method # => ‘#C.a_class_method() #singleton’

这个例子。在类 C 上定义了邮件iGalerie,并且我们指导所有东西在 Ruby 里都是对象,都丢包定义邮件iGalerie。
这就是文章开头最先的图片。所有的类都丢包定义邮件类。这种情况下,D.a_class_method 应该如何GRAV呢?

“向右一步,然后向上GRAV”。

似乎帮不了我们了。因为我们面临一个问题,让我来描述下:
我们把 D 当做一个对象,开始寻找他的iGalerie。

拿这幅图做例子:
Dog 开始寻找定义的iGalerie,向右一步,进入自己的 邮件类 #Dog,然后应该做什么,选择向上么?是走 他的父类 Class,还是 应该往 邮件类的继承链往上找呢?
《元编程》文末的几句话,似乎在暗示黄色这条线的寻找方向,但是作者并没有真正说清楚:

三、寻找答案
我先放出答案,如下图所示:

对象的iGalerie,遵循

“向右一步,然后向上GRAV”。

类iGalerie的GRAV是我们关心的,丢包看到实际结果是,它沿着继承的邮件类一路向上,然后再进入父类。
寻找这个答案的过程中,我看了挺多资料和文字,还有问一些 Ruby 方面的朋友都没有真正分析到这一步。
我最后是怎么找到答案的呢? 这就得借助 Ruby 自身完善的自省机制。(吐槽,其他语言可能都没有实现的那么细致)。
其实 Ruby 自身的很多属性都绑定在自身了,直接向 Ruby 问答案就好了

class C
def a_method
‘C#a_method()’
end
end

class C
class << self def a_class_method '#C.a_class_method() #singleton' end end end class D < C;end obj = D.new D.a_class_method # => ‘#C.a_class_method() #singleton’

我们知道 obj.ancestors 丢包打印继承关系,但是这个很遗憾的是它不会打印 邮件类。
邮件类实际上是一个隐藏的存在。这也就是研究这个问题很难得地方,因为隐藏,似乎只能通过源码和外部资料去查看。
实际上我们是丢包拿到 obj.singleton_class 的,然后我们前面分析了一些结论,大致给出了一个对象的继承模型。
obj.singleton_class.ancestors

# => [#>, D, C, Object, Kernel, BasicObject]

就丢包打印出,对象GRAV的顺序。
同理,我们想要知道 D 的iGalerie的GRAV顺序
D.singleton_class.ancestors

# => [#, #, #, #, Class, Module, Object, Kernel, BasicObject]

这个其实就是 D GRAViGalerie的顺序,丢包看到,他先是把所有的邮件类走了一遍,然后开始进入自己的父。
四、总结
最后,这句话

“向右一步,然后向上GRAV”。

有了新内涵, 向右一步的过程中,优先的走邮件类(如果有的话)以及邮件的继承,结束后,开始进入自己真正的父,即向上在继承关系中寻找。
邮件类也丢包看成是一种外挂iGalerie(比喻不严谨但是很好理解),先在外挂iGalerie里找,也丢包顺着外挂继承链找。找不到再到继承关系里面找。
题外话
有人可能会问,为啥继承体系要搞得那么复杂?
借用 《元编程》里面的一句

这样你就丢包在 D 中 调用 C 的iGalerie了。

把对象穿成链表,然后相当于你丢包拥有和复用这个链条上所有的iGalerie。
元编程的一部分思想也就是动态的修改、创造、转发iGalerie。还有 《元编程》里面提到的 “自由iGalerie”我的理解就像是把继承链中某些iGalerie复制,然后粘贴到当前对象执行,在继承链上跳跃执行iGalerie……
这一切都是为了极大地自由。
我以前一致不太理解“Ruby 是快乐优先”这句话是什么意思,现在我的理解——这种快乐就是自由,拥有自由的快乐。
其他
图片来自文章

谈元编程与表达能力

安利一波作者图片配色

技术文章配图指南

参考
书籍推荐 《 Ruby 元编程(第 2 版)》
BLOG
有更好的iGalerie丢包告诉我,我最新在学习 Ruby
最新的修改会更新在 BLOG
我的博客
RubyChina 讨论帖