是否可以在方法中访问块的范围?

时间:2012-02-12 02:32:58

标签: ruby

我想编写方法(define_variables),它可以获得block并使用其中定义的变量。可能吗?例如,我想输出5:

module A
  def self.define_variables
    yield
    puts a # not 5 :(
  end
end

A::define_variables do
  a = 5
end

也许有一些eval技巧,但还没有找到任何人。

2 个答案:

答案 0 :(得分:5)

简而言之,没有。在您调用yield之后,块中定义的那些变量已消失(有点像我们将要看到的),除了返回的内容 - 这就是范围的工作原理。在您的示例中,5仍然存在,因为它由块返回,因此puts yield将打印5。使用此方法,您可以从块{:a => 5}返回一个哈希值,然后以这种方式访问​​多个“变量”。在Ruby 1.8(在IRb only中),你可以这样做:

eval "a = 5"
a # => 5

虽然我不知道eval块的内容。无论如何,in Ruby 1.9 the scope of eval was isolated这会给你一个NameError。您可以在Binding的上下文中执行eval

def foo
  b = yield
  eval(a, b) + 2
end

foo do
  a = 5
  binding
end # => 7

在我看来,你要做的是在Ruby中模拟宏,这是不可能的(at least not pure Ruby),我不鼓励使用我提到的任何“变通办法”上方。

答案 1 :(得分:2)

同意这有点倒退,安德鲁的解释是正确的。但是,如果您的用例是定义变量,那么已有class_variable_setinstance_variable_set方法可用于此:

module A
  def self.define_variables(vars = {})
    vars.each { |n, v| class_variable_set n, v }
    puts @@a
  end
end

A::define_variables :@@a => 5

上面更多的是如何在您发布的代码中工作而不是推荐的示例。