2012-08-02 102 views
1

这是关于此answer的后续,关于ruby 1.8.7的符号#to_proc每次调用都会生成一个新的proc。红宝石1.8.7 to_proc创建空阵列

似乎有更多的事情比答案建议。

下面是一些示例代码:

def ctob 
    h=Hash.new(0) 
    ObjectSpace.each_object(Object) {|e| h[e.class]+=1 } 
    h 
end 
r=(0...1000) 
p ctob 
r.map(&:to_i) 
p ctob 

这表明正在创造大约有一千阵列。这表明大约有一千个是空的:

c=0; ObjectSpace.each_object(Array){|e| c+=1 if e.empty? } 

另一个有趣的事情是,只有一个Proc对象存在。这表明to_proc只被调用一次。 (如果我第二次使用符号调用map,可能会创建另一个。)

如果我更改地图调用以使用块,则不会创建这些数组。这也可以解释为什么Andrew Grimm的缓存对基准测试没有帮助。为什么创建这些数组?

UPDATE

显然是从一个符号创建一个进程创建每次被称为时间空数组。

如果我更换map线上面

pr=:to_i.to_proc; r.map(&pr) 

导致创建阵列,但这种

pr=proc{|e|e.to_i}; r.map(&pr) 

没有。类似的事情发生,如果我只做pr.call(价值)。

(何时是proc不是proc?)

回答

0

我想我找到了答案。

我看着的ActiveSupport 2.2,发现这为Symbol#to_proc体:

Proc.new { |*args| args.shift.__send__(self, *args) } 

args是数组。由于范围的每个成员都作为单个参数传递,因此它将转换为1个元素的数组。这一个元素被移出,留下一个空的数组。所以它不会创建空数组,它只是在处理参数后才将它们留在后面。

我使用2 ARG PROC也做了测试:

[1,2,3,4].inject(&:+) 

这留下1个元件的阵列(原始第一元件是当前总和)。

我的假设是1.8.7做了类似的事情。我很想知道1.9是如何改变它的。