2013-08-17 152 views
1

任何人都可以解释以下行为:访问类变量无法

class X 
    @@x = 1 
end 

X.class_eval { @@x } #=> NameError: uninitialized class variable ... 
X.class_eval { class_variable_get :@@x } #=> 1 

经测试,在MRI 1.8.7,1.9.2,1.9.3和2.0.0具有相同的结果。为什么我不能直接在X.class_eval { ... }区块内使用@@x

回答

1

发生这种情况类变量访问在词汇范围内。红宝石实际上给你,当你运行你的代码,暗示了这个警告:

警告:从顶层

这表明,类变量是在顶层范围被决定的类变量访问。我们可以证明这是由class_eval内部分配,然后外面访问它真:

X.class_eval { @@x = 42 } 
@@x #=> 42 

这证明类变量的词汇性质导致class_eval(其变异self)没有任何效果。

可惜我不能找到一个很好的参考记录这种行为,虽然有关类变量赋值一些其他具体是覆盖在Programming Ruby’s section “Scope of Constants and Variables”

注意X.class_variable_get(:@@x)也将42因为X@@x从顶层继承。我们可以通过创建一个没有明确的@@xClass.new.class_variable_get(:@@x) #=> 42的新班级来看到这一点。

+1

这只是*许多例子中的一个,为什么你应该实际读*警告。有人会努力编写这些警告来帮助您发现错误。不读它们有点粗鲁! –

+0

@JörgWMittag,你为什么认为我没有*阅读*警告?我决定不把它们包括在问题中,这可能是一个错误,但那是另一回事,不是吗? – Alexis