访问常量

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

module A; end A.instance_eval{B=1} B #=> 1 A::B #=> uninitialized 

这样做的惯用方法是

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

至于为什么它不起作用,在Ruby 1.8和1.9.2+中(它在1.9.1中有所不同),常量查找是词法范围的。 我找到了一篇很好的博客文章并附上解释。 报价:

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

instance_eval也是如此。

因为。 。 。

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

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

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 
 module A; end A.class_eval{B=1} B # Undefined A::B # 1 

至于它为何起作用,我不太确定。 我偶尔会在创建非常小的框架(例如小型本征碰撞机)时使用这样的元编程,但不能在日常工作中使用。