笔记:Ruby方法查找实验

导航关联

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>

Mark24

Everything can Mix.