访问常量

时间:2012-04-09 19:37:39

标签: ruby constants

为什么我不能从'A'访问以下'B',但可以从主环境访问?

module A; end
A.instance_eval{B=1}

B #=> 1
A::B #=> uninitialized

4 个答案:

答案 0 :(得分:4)

来自documentation of instance_eval(强调我的):

  

在接收器(obj)的上下文中计算包含Ruby源代码或给定块的字符串。 为了设置上下文,变量self在代码执行时设置为obj ,使代码可以访问obj的实例变量。

这里没有更多的事情要做。特别是,常量赋值在块的封闭上下文中运行。观察:

irb(main):001:0> module A
irb(main):002:1>   module B; end
irb(main):003:1>   B.instance_eval { C = 1 }
irb(main):004:1> end
=> 1
irb(main):006:0> A::C
=> 1

答案 1 :(得分:4)

因为。 。

。 。 。未在类或模块中定义的常量被赋予全局范围。

对于常量定义而言,重要的是封闭的词汇范围,而不是当前的接收者或self的值。

答案 2 :(得分:3)

这样做的惯用方法是

 A.const_set(:B, 1)
 A::B #=> 1

至于为什么它不起作用,在Ruby 1.8和1.9.2+中(它在1.9.1中有所不同),常量查找是词法范围的。我发现了一个很好的blog post并附有解释。引用:

  

请注意,这些规则适用于常量定义和查找。   在1.8和1.9.2中,class_evaluated块中定义的常量将   在封闭的词汇范围中定义,而不是在范围内   接收者。

instance_eval同样如此。

答案 3 :(得分:1)

module A; end
A.class_eval{B=1}
B # Undefined
A::B # 1

至于它为何起作用,我不太确定。我偶尔会在创建像小特征碰撞器这样的元框架时使用这样的元编程,但不能在日常工作中使用。