我正在使用ruby 1.8.7(2011-12-28 patchlevel 357)[i686-darwin11.2.0] 我正在玩Kernet :: eval方法。
The binding may be a Binding object or a Proc object.
def eval(string, *binding_filename_lineno)
end
我有以下test.rb
require 'pp'
p = proc { local_var = 'value'; puts "initializing local_var as #{local_var}" }
p.call()
pp eval("local_variables", p)
调用ruby test.rb打印
initializing local_var as value
["p"]
不应该返回["p", "local_var"]
?
我也看到Ruby 1.9.3 eval只接受一个Binding对象。
答案 0 :(得分:2)
binding
方法返回已创建proc的绑定,并且不关心proc内容。
require 'pp'
some_local_var = 'hello'
p = proc { local_var = 'value'; puts "initializing local_var as #{local_var}" }
p.call()
pp eval("local_variables", p) #=> ['p', 'some_local_var']
变量local_var
仅在proc执行的短时间内存在。你之前执行它的事实并不意味着它仍然在那里(可能是如果GC还没有运行,但你不应该使用它)。一般来说,你应该把它视为无法到达。但是,由于proc可以访问它自己的绑定并且它自带绑定,你可以通过在proc之外声明内部变量来欺骗它:
require 'pp'
local_var = 'hello'
p = proc { local_var = 'value'; puts "initializing local_var as #{local_var}" }
pp eval("local_var", p) #=> hello
p.call()
pp eval("local_var", p) #=> value
这可用于创建行为类似于对象的过程:
def get_counter
i = 0
proc { p i+=1 }
end
a = get_counter
b = get_counter
5.times { a.call } #=> 1 2 3 4 5
3.times { b.call } #=> 1 2 3
eval('i', a) #=> 5
eval('i', b) #=> 3
3.times { a.call } #=> 6 7 8
然而,这不是最佳实践,并且是Ruby程序中大多数内存泄漏的主要原因。
在Ruby 1.8.7中,您可以传递proc而不是绑定,但是eval在内部调用proc上的binding
方法。这已在以后删除,因此现在您需要明确地提取它。
pp eval("local_variables", p.binding)
更新:
由于这是红宝石,显然我们可以做任何事情,自然有一种方法可以访问proc内部变量:
require 'pp'
proc_binding = nil;
p = proc { local_var = 'value'; puts "initializing local_var as #{local_var}"; proc_binding = binding }
p.call()
pp eval("local_variables", proc_binding) #=> ["proc_binding", "p", "local_var"]
要小心 - 将内部绑定存储在变量中意味着即使在proc运行之后也会引用local_var
,因此GC不会收集它。此外,由于proc引用它并且尚未清理,因此不会在本地重新声明,这几乎是一种破坏生活的快速方法。这些技术在一些非常罕见的情况下可能会有用,但它们通常会导致很多难以调试的问题。