Ruby中方法继承、方法查找路径、constant查找路径 @(Ruby)
可以看到,B不仅继承了A的实例方法,还继承了A的 singleton方法。
输出结果为:
1 singleton 2 extend 3 prepend 4 klass 5 include 6 super此时继承链为
> Klass.ancestors => [Prepend, Klass, Include, Super, Object, Kernel, BasicObject] > thing.singleton_class.ancestors => [#<Class:#<Klass:0x007fe42a89d5a8>>, Extend, Prepend, Klass, Include, Super, Object, Kernel, BasicObject]可以看到实例 thing 上的方法的寻找路径是根据它的单例类的继承链来决定的。
常量的查找是按照下面的规则进行的: - 首先查找Module.nesting路径,这个Module.nesting跟方法的调用没关系,而是根据方法定义的位置而确定的, - 否则查找Module.nesting.first.ancestors - 如果Module.nesting.first是nil或者module,查找Object.ancestors
1、通过Module.nesting查找,路径为[A].
class A def get_c C end end class B < A module C; end end B.new.get_c => "NameError: uninitialized constant A::C"可以看到,虽然B中定义了常量C,但是get_c没有从B中开始查找,而是从自己被定义的模块A开始查找,找不到而报错。
2、Module.nesting找不到,则从Module.nesting.first.ancestors开始查找,此时为会去A的父类AParent中查找。
class AParent C = 'AParent' end class A < AParent def get_c C end end class B < A C = 'in B' end B.new.get_c => "AParent"3、 如果Module.nesting.first是nil或者module类型,则从Object查找:
class AParent C = 'AParent' end class A < AParent module M def get_c C end end end class B extend A::M end B.get_c => "NameError: uninitialized constant A::M::C"因为Object中没有C常量,因此会报错,我们为Object加上常量C,此时运行结果如下:
class Object C = 'In Object' end class AParent C = 'AParent' end class A < AParent module M def get_c C end end end class B extend A::M end B.get_c => "In Object"这是一段Ruby内建的常量查找代码,使用了 binding.eval ,不管在任何地方调用,都能 保证查找的起点都是从它被定义的地方。
class Binding def const(name) eval <<-CODE, FILE, LINE + 1 modules = Module.nesting + (Module.nesting.first || Object).ancestors modules += Object.ancestors if Module.nesting.first.class == Module found = nil modules.detect do |mod| found = mod.const_get(#{name.inspect}, false) rescue nil end found or const_missing(#{name.inspect}) CODE end end参考文章: https://cirw.in/blog/constant-lookup.html http://pascalbetz.github.io/ruby/2016/03/14/lookup-path/
