Mark24
笔记:Ruby方法查找实验
导航关联
超类链 继承查找
一句话就是超类链继承查找。
这里是最朴素的情况,依次注释 run 方法打印结果,符合预期。一定是链条上的最近的响应的run方法。
class A # 默认是Object
def run
pp "A"
end
end
class B < A
def run
pp "B"
end
end
class C < B
def run
pp "C"
end
end
class D < C
def run
pp 'D'
end
end
D.new.run
Mixin情况 Module#include
class A # 默认是Object
def run
pp "A"
end
end
class B < A
def run
pp "B"
end
end
class C < B
def run
pp "C"
end
end
module E
def run
pp "E"
end
end
module F
def run
pp "F"
end
end
class D < C
include E
include F
end
D.new.run
D.ancestors 的结果就是 [D, F, E, C, B, A, Object, PP::ObjectMixin, Kernel, BasicObject]
可以注释 include F
include E
查看情况,也符合预期
Module#include 嵌套 和 搜索常量
这里为了简化,把 A~D 去掉了,他们是不影响结果的。这里只关注最先命中。
module E
def run
pp "E"
end
module F
def run
pp "F"
end
end
end
class D
include E
include F
end
D.new.run
print D.ancestors
# output >>>
# "F"
# [D, E::F, E, Object, PP::ObjectMixin, Kernel, BasicObject]
include F 在当下的 D中找不到,则会进入上面的词法作用域开始查找。最终找到了 E::F 。
因为 class、module 会创建独立的作用域,并且在Ruby内部是 独立的 RClass 所以即使是 F 嵌套在 E内部,也是无所谓的,这两个宛如不相关的两部分。所以 就跟直接写F一样。最后F优先响应。
Module#prepend
prepend 会把类放在 目标类的下面。顺如可以通过祖先类看出来。
class A # 默认是Object
def run
pp "A"
end
end
module E
def run
pp "E"
end
end
module F
def run
pp "F"
end
end
class B < A
prepend E
include F
end
B.new.run
pp B.ancestors
# 情况1:仅仅 include F
# "F"
# [B, F, A, Object, PP::ObjectMixin, Kernel, BasicObject]
# 情况2: 仅仅 prepend E
# "E"
# [E, B, A, Object, PP::ObjectMixin, Kernel, BasicObject]
# 情况3:
# include E
# prepend F
# "E"
# [E, B, F, A, Object, PP::ObjectMixin, Kernel, BasicObject]
# 情况4:
# prepend E
# include F
# "E"
# [E, B, F, A, Object, PP::ObjectMixin, Kernel, BasicObject]
情况2 简单的说下
E -> B(目标类) -> A
形成这种关系的底层实现是复制了一份目标类,重新和E关联起来。
这部分感兴趣可以详细参考 《Ruby原理剖析》6.2 Page163
类方法 查找顺序
这里一段,我们不关心 对象和类了。他们这一部分结束。
我们现在关系 元类 的问题,也就是类方法。(PS: 类方法,和 类的单例方法,其实是保存在一处 也就是 A类的 类方法 和 A类的实例方法,最终结果都绑定在 #A上。)
class A
def self.run
puts 'A'
end
end
class B < A
def self.run
puts "B"
end
end
class C < B
# def self.run
# puts "C"
# end
end
C.run
pp C.singleton_class.ancestors
B
# output >>>>>
# [#<Class:C>,
# #<Class:B>,
# #<Class:A>,
# #<Class:Object>,
# #<Class:BasicObject>,
# Class,
# Module,
# Object,
# Kernel,
# BasicObject]
这段代码适合不断地注释查看结果。响应结果是和 C.singleton_class.ancestors 链条上保持结果一致。符合预期。
他会顺着 单例类的 超类链条 查找,结束后进入 自己的 类(Class)查找然后 进入父类的超类链查找。
其他的情况,module下定义方法不能被直接使用。再复杂的我还没见过,如果是我会主动规避掉。实在不行就先自省检查之后,再执行。 等遇到的复杂的再分析。
跳出来看,我觉得 看完了一圈 Ruby各种教程,脑子太多容易糊涂。实际上,就单纯从结果上来看,实际上很清晰,Ruby设计的也很简单。背后就是指针嘛。
while 循环 顺着 super往上找,一直到找到未知。
简单验证下 superclass 链条 (超类链),结果是保持一致的。
pp C.singleton_class.ancestors
puts '-----'
pp C.singleton_class
pp C.singleton_class.superclass
pp C.singleton_class.superclass.superclass
# output >>>>>>>>
# [#<Class:C>,
# #<Class:B>,
# #<Class:A>,
# #<Class:Object>,
# #<Class:BasicObject>,
# Class,
# Module,
# Object,
# Kernel,
# BasicObject]
# -----
# #<Class:C>
# #<Class:B>
# #<Class:A>