根据文档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
查找“全局”常量:
class C; end
C.const_get(:Array) #=> Array
然而,这就是我感到困惑的地方 - 模块不是Object
的子类。那么为什么我仍然可以使用const_get
从模块中查找“全局”常量?为什么以下工作?
module M; end
M.const_get(:Array) #=> Array
如果文档正确 - const_get
只需查找接收者或其超类下定义的常量。但是在上面的代码中,Object
不是M
的超类,那么为什么可以查找Array
?
由于
答案 0 :(得分:11)
你是混淆的正确...文档没有说明Ruby在Modules
中查找常量并且已被修改to state this explicitly。如果在常规层次结构中未找到常量,则Ruby会从Object
重新开始查找,可能是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
但是,在这两个地方,访问Object
等Array
等常量都很好(感谢上帝!)。发生的事情是Ruby维护着一个“打开的模块定义”列表。如果常量具有明确的范围,例如LookHereOnly::Foo
,则仅 LookHereOnly
及其包含的模块将被搜索。如果未指定范围(如上例中的Foo
),Ruby将查看打开的模块定义以查找常量Foo
:M::N
,然后M
,最后Object
。最顶层打开的模块定义始终为Object
。
所以M::N.const_get :Foo
相当于在打开的课程只有Foo
和M::N
时访问Object
,就像我示例的最后一部分一样。
我希望我能做到这一点,因为我仍然对自己不断的查询感到困惑: - )
答案 1 :(得分:2)
我想出了以下脚本来加载名称间隔常量:
def load_constant(name)
parts = name.split('::')
klass = Module.const_get(parts.shift)
klass = klass.const_get(parts.shift) until parts.empty?
klass
end
答案 2 :(得分:0)
只要我们不检查错误,您可以:
def load_constant(name)
name.split('::').inject(Module) do |mod_path, mod_to_find|
mod_path.const_get(mod_to_find)
end
end