Ruby中const_get的混乱行为?

根据文档mod.const_get(sym)“返回mod中的命名常量的值。

我也知道,const_get默认可能会查找接收器的继承链。所以以下作品:

class A; HELLO = :hello; end
class B < A; end
B.const_get(:HELLO) #=> :hello

我也知道Ruby子类Object中的类,所以即使接收者是普通类,也可以使用const_get来查找’global’常量。

class C; end
C.const_get(:Array) #=> Array

但是,这是我困惑的地方 – 模块不会对象进行子类化。那么为什么我仍然可以使用const_get从模块中查找“全局”常量?为什么以下工作?

module M; end
M.const_get(:Array) #=> Array

如果文档正确 – const_get只需查找接收器或其超类下定义的常量。但是在上面的代码中,Object不是M的超类,那么为什么可以查找Array?

谢谢

最佳答案
你是正确的被困惑…该文档没有声明Ruby为模块中的常量查找特殊情况,并已修改to state this explicitly.如果在常规层次结构中找不到常量,Ruby将重新启动查找对象,可以是found in the source

固定查找本身可能会令人困惑。举个例子:

module M
  Foo = :bar
  module N
    # Accessing Foo here is fine:
    p Foo # => bar
  end
end
module M::N
  # Accessing Foo here isn't
  p Foo  # => uninitialized constant M::N::Foo
end
p M::N.const_get :Foo  # => uninitialized constant M::N::Foo

不过,在这两个地方,访问像Array这样的Object级常量都很好(感谢上帝!)。发生什么事情是Ruby维护了一个“已打开的模块定义”的列表。如果一个常量有一个明确的范围,那么说LookHereOnly :: Foo,那么只有LookHereOnly和它的包含的模块将被搜索。如果没有指定范围(像上面的例子中的Foo),Ruby将查看已打开的模块定义,以找到常量Foo:M :: N,然后M和最后Object。最上面打开的模块定义总是Object。

所以M :: N.const_get:Foo相当于在打开的类只有M :: N和Object时访问Foo,就像我的例子的最后一部分一样。

我希望我有这个权利,coz我仍然通过不断的查找自己感到困惑:-)

转载注明原文:Ruby中const_get的混乱行为? - 代码日志