使用[..](切片)方法引用数组时,Ruby是否会创建副本?

时间:2017-04-20 14:22:18

标签: arrays ruby memory slice

我想循环一个数组的片段。我基本上有两个主要选择。

ar.each_with_index{|e,i|
   next if i < start_ind
   break if i > end_ind
   foo(e)
   #maybe more code...
}

我认为更优雅的另一种选择是运行:

ar[start_ind..end_ind].each{|e|
   foo(e)
   #maybe more code...
}

我担心Ruby可能会在引擎盖下创建一个巨大的阵列并进行大量的内存分配。或者是否有一些“更聪明”的东西没有创建副本?

2 个答案:

答案 0 :(得分:3)

你可以做一个索引值的循环......不像你的第二个解决方案那么优雅,但经济实惠。

null

答案 1 :(得分:1)

您可能想参考方法&#39; C源代码,但读取代码需要一些时间。我可以帮助你吗

首先:each_index

它在C中的源代码很棘手,但归结为类似于&#39;每个&#39;看起来像

VALUE rb_ary_each(VALUE ary) {
    long i;

    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
    for (i=0; i<RARRAY_LEN(ary); i++) {
    rb_yield(RARRAY_AREF(ary, i));
    }
    return ary;
}

它本身不会在内部创建任何其他数组。它实际上做的是简单地循环遍历元素,获取每个元素并将其传递到提供的块(rb_yield部分)。您提供的块内实际上是一个不同的故事。

第二:[...]。每个

你实际上必须注意到它是两个函数调用。第二个是每个&#39;对我们没什么兴趣,因为它在上面描述了第一个函数调用是&#39; []&#39;。从逻辑上讲,你希望它输出一个子数组作为变量,它必须至少是临时存储的。

让我们验证一下。 C的源代码相当长,但对你来说最重要的是:

VALUE rb_ary_aref(int argc, const VALUE *argv, VALUE ary) {
    // some code 
    if (argc == 2) {
        beg = NUM2LONG(argv[0]);
        len = NUM2LONG(argv[1]);
        if (beg < 0) {
            beg += RARRAY_LEN(ary);
        }
        return rb_ary_subseq(ary, beg, len);
    }
    // some more code 
}

它实际上是一个函数调用,如ar [start_ind,end_ind]而不是ar [start_ind..end_ind]。差异并不重要,但这种方式更容易理解。

回答你问题的事情称为&#34; rb_ary_subseq&#34;。正如您可能从其名称中猜测或从其来源中学习,它实际上确实创建了一个新数组。因此,它会在大小等于或小于给定数组的情况下创建副本。

您想要考虑功能调用的计算成本,但问题是关于内存。