2012-02-12 39 views
2

我想写一个方法(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,但还没有找到任何人。

+3

这是什么实际使用情况?这对我来说似乎倒退了。 – 2012-02-12 02:42:34

+1

如果您想利用在已传递的块内进行的一些计算,最好的办法是从该块返回一些内容并对其进行处理。依赖传递的proc中的局部变量的命名没有多大意义。什么是保证某人使用“a”作为变量?当你不想要的时候,你会如何防止任意proc跺跺自己的变量? – 2012-02-12 04:24:39

+0

我想为简单的控制台游戏制作一个'GameWorld'模块,这个模块有'load'和'run'方法。 load方法加载game_objects并将它们存储在数组中,'run'来描述它们之间的一些交互。在GameWorld的范围中,我可以访问game_objects数组并输出一些信息(健康状况,分数等)。只是为了“对称”和学习的目的,我试图用这两种方法使用块。现在,我将对象直接加载到模块的常量“game_objects”中。无论如何,非常感谢您的帮助,现在我们越来越清楚范围和区块的工作方式。 – evfwcqcg 2012-02-12 04:54:08

回答

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),和我劝阻使用上面提到的任何“解决方法”。

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 

以上是你越已经发布,而如何将代码内工作的例子比推荐。

+0

用实例/类变量绕过整个范围问题肯定会让'')''更容易推理。 – 2012-02-12 03:10:09

+0

我试图看看我可以用给定的代码来完成工作。看着这很聪明。 – ericraio 2012-02-12 03:19:31

相关问题