在ruby中块中定义的常量的常量定义的上下文是什么?

时间:2012-11-20 18:10:38

标签: ruby metaprogramming

这是一个关于你的面条的问题。

在使用class_eval并将类作为接收器进行评估的块中,方法声明和常量声明之间似乎存在差异。这里有一些代码可以证明这种差异:

module X
  def save_block(&block)
    @block = block
  end
end

module Y
  extend X
  save_block do
    SOME_CONSTANT = 1
    def meth
      "a method"
    end
  end
  def self.included(m)
    m.class_eval &@block
  end
end

class Z
  include Y
end

class W
  include Y
end

至少在Ruby 1.9.3中执行此代码会导致以下错误:

warning: already initialized constant SOME_CONSTANT

我没想到。首先考虑meth所在的位置:

Z.instance_methods(false)
=> [:meth]

W.instance_methods(false)
=> [:meth]

并且Y没有任何实例方法:

Y.instance_methods(false)
=> []

这是有道理的,因为该块是以ZW作为class_eval的接收者执行的。但是,常量是不同的,因此出现错误消息,如下所示:

Y.constants(false)
=> [:SOME_CONSTANT]

Z.constants(false) 
=> []

W.constants(false)
=> []

这里,常量最终在Y中定义(出于某些奇怪的原因),因此当块第二次执行时,常量SOME_CONSTANT已经定义。

我非常期待一些启示。

更新(2012/11/19):

正如@phoet在下面指出的那样(对我的回答的评论的回应),常量在块的lexical scope中定义,也就是说,在最初定义块的范围内。在我的例子中,这将是Y。

1 个答案:

答案 0 :(得分:1)

如本问题中所述Accessing a constant常量处理是在它的“词法范围”内,意味着它们被定义的上下文,而不是它们被执行的上下文。