我最近发现Ruby(2.2.1)有一些有趣的"行为。
module Foo
class Foo
end
class Bar
end
end
Foo.const_get('Foo') #=> Foo::Foo
Foo.const_get('Bar') #=> Foo::Bar
Foo.const_get('Foo::Foo') #=> Foo
Foo.const_get('Foo::Bar') #=> NameError: uninitialized constant Foo::Foo::Bar
Foo.const_get('Foo::Foo::Bar') #=> Foo::Bar
Foo.const_get('Foo::Foo::Foo::Bar') #=> NameError: uninitialized constant Foo::Foo::Bar
Foo.const_get('Foo::Foo::Foo::Foo::Bar') #=> Foo::Bar
Foo.const_get('Foo::Foo::Foo') #=> Foo::Foo
Foo.const_get('Foo::Foo::Foo::Foo') #=> Foo
Foo.const_get('Foo::Foo::Foo::Foo::Foo') #=> Foo::Foo
Foo.const_get('Foo::Foo::Foo::Foo::Foo::Foo') #=> Foo
这有点令人惊讶。我的理解是const_get
首先在接收器的常量集合中查找常量,然后查看Object的常量。好的。那么为什么上面的第四个Foo#const_get
失败而第三个没有呢?
我也很好奇为什么在模块和课程之间调用Foo#const_get
,这取决于你添加了多少::Foo
。
答案 0 :(得分:11)
如果提供了命名空间的类名,则此方法将以递归方式查找常量名称。
所以Foo.const_get('Foo::Bar')
基本上与Foo.const_get('Foo').const_get('Bar')
相同。使用这种解释,您的结果是有意义的。
你的第三个例子:
Foo.const_get('Foo::Foo')
与
相同Foo.const_get('Foo').const_get('Foo')
第一个const_get
查看顶级Foo
(模块)中定义的常量,并查找嵌套类。所以整个事情实际上变成了:
Foo::Foo.const_get('Foo')
第二个调用然后查看该类,首先查看任何包含的常量(找不到),然后查看它的祖先。 Object
是一个祖先,并且顶级Foo
模块作为常量,因此找到并返回。
这也解释了添加额外::Foo
时的更改。交替发生在查找嵌套类的顶级模块上的const_get
和查找继承链并查找顶级模块的嵌套类之间。
还可以解释引发异常的第四个例子Foo.const_get('Foo::Bar')
。它相当于
Foo.const_get('Foo').const_get('Bar')
第一部分Foo.const_get('Foo')
与上面的情况相同,评估为Foo::Foo
,所以整个事情现在实际上变成了:
Foo::Foo.const_get('Bar')
现在,嵌套的Foo
类不包含Bar
常量,并且查找继承链,Object
也没有,因此结果为NameError
。