Ruby中const_get的混乱行为?
根据文档Ruby中const_get的混乱行为?,ruby,Ruby,根据文档mod.const_get(sym)“返回mod中命名常量的值。” 我还知道,默认情况下,const_get可以查找接收方的继承链。因此,以下工作: class A; HELLO = :hello; end class B < A; end B.const_get(:HELLO) #=> :hello 然而,这就是我感到困惑的地方——模块并不是对象的子类。那么,为什么我仍然可以使用const\u get从模块中查找“全局”常量呢?为什么下面的工作 module M; end
mod.const_get(sym)
“返回mod中命名常量的值。”
我还知道,默认情况下,const_get
可以查找接收方的继承链。因此,以下工作:
class A; HELLO = :hello; end
class B < A; end
B.const_get(:HELLO) #=> :hello
然而,这就是我感到困惑的地方——模块并不是对象的子类。那么,为什么我仍然可以使用const\u get
从模块中查找“全局”常量呢?为什么下面的工作
module M; end
M.const_get(:Array) #=> Array
如果文档正确-const_get
只需查找接收器或其超类下定义的常量。但是在上面的代码中,对象
不是M
的超类,那么为什么可以查找数组
谢谢您的困惑是正确的。。。文档没有说明Ruby为查找模块中的常量提供了一个特例,并且已经修改。如果在正常的层次结构中找不到常量,Ruby会根据需要从对象
重新启动查找
常量查找本身可能有点混乱。以以下为例:
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
不过,在这两个地方,访问对象
级别的常量(如数组
)都很好(感谢上帝!)。现在的情况是Ruby维护了一个“打开的模块定义”列表。如果常数具有显式作用域,例如LookHereOnly::Foo
,则将搜索onlyLookHereOnly
及其包含的模块。如果没有指定作用域(如上例中的Foo
),Ruby将通过打开的模块定义查找常量Foo
:M::N
,然后是M
,最后是对象
。最顶端打开的模块定义总是对象
因此M::N.const\u get:Foo
相当于在打开的类只有M::N
和Object
时访问Foo
,就像我示例的最后一部分一样
我希望我没有弄错,因为我自己仍然对不断的查找感到困惑:-)我想出了以下脚本来加载名称间隔的常量:
def load_constant(name)
parts = name.split('::')
klass = Module.const_get(parts.shift)
klass = klass.const_get(parts.shift) until parts.empty?
klass
end
只要我们不检查错误,您就可以:
def load_constant(name)
name.split('::').inject(Module) do |mod_path, mod_to_find|
mod_path.const_get(mod_to_find)
end
end
请注意,这与:
的行为不匹配SomeModule::SomeGlobalConstant
将导致错误,而SomeModule.const\u get(:SomeGlobalConstant)
将工作。知道它为什么会这样做吗?在什么情况下这会有用?@sepp2k:不确定它是否有用,但我试图解释我认为它背后的逻辑。这不是直观的,但M::N问题是由于词法范围。如果您执行模块M;模块N;结束;结束
,M的内容在N的词法范围内(由于嵌套,M从N可见)。具有模块M::N;end
,M不可见,因为包含范围是顶层。就我个人而言,我尽量避免以M::N形式定义类和模块,这也是因为如果M还不存在的话,这是一个错误。。。试试eval(“M::N”),JRuby也可以用这种方法做一些有趣的事情是的,它是邪恶的
def load_constant(name)
name.split('::').inject(Module) do |mod_path, mod_to_find|
mod_path.const_get(mod_to_find)
end
end