6

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

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

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

4 回答 4

4

从(强调我的)的文档中: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
于 2012-04-09T19:49:42.450 回答
4

因为 。. .

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

常量定义重要的是封闭的词法范围,而不是当前的接收者或self.

于 2012-04-09T19:54:47.343 回答
3

这样做的惯用方法是

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

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

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

对于instance_eval.

于 2012-04-09T19:43:46.257 回答
1
module A; end
A.class_eval{B=1}
B # Undefined
A::B # 1

至于它为什么起作用,我不太确定。在创建诸如 Small Eigen Collider 之类的元框架时,我偶尔会使用这样的元编程,但不会在日常工作中使用。

于 2012-04-09T23:42:01.187 回答