为什么我不能从'A'访问以下'B',但可以从主环境访问?
module A; end
A.instance_eval{B=1}
B #=> 1
A::B #=> uninitialized
答案 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
至于它为何起作用,我不太确定。我偶尔会在创建像小特征碰撞器这样的元框架时使用这样的元编程,但不能在日常工作中使用。