每个迭代器在ruby中的行为

时间:2017-04-18 05:45:15

标签: ruby

为什么这段代码会输出[1, 2, 3, 4, 5]而不是[2, 3, 4, 5, 6]

x = [1, 2, 3, 4, 5]
x.each do |a|
  a + 1
end

我在https://ruby-doc.org/core-2.2.0/Array.html#method-i-each查看了each的来源。这样的东西写在那里。

              VALUE
rb_ary_each(VALUE array)
{
    long i;
    volatile VALUE ary = array;

    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;
}

有人可以解释一下吗?

2 个答案:

答案 0 :(得分:3)

它输出对象,您正在调用each,因为这是each的返回值。

如果您只想打印a + 1,您应该实际输出:

x.each do |a|
  puts a + 1
end

或者,如果您所需的结果为[2, 3, 4, 5, 6],则需要Enumerable#map,而不是each

x.map { |a| a + 1 }
#=> [2, 3, 4, 5, 6]

答案 1 :(得分:1)

让我通过关键线。

从这一点开始,它就是&#39; ary&#39;在逻辑上等于数组。请注意,较新版本的Ruby(如2.4.0!

)中不存在该行
volatile VALUE ary = array;

我跳过了RETURN_SIZED_ENUMERATOR,因为给出了一个块。请参阅include / ruby​​ / intern.h中的源代码。

接下来,我们进入&#39; for&#39;对于'ary&#39;的每个元素阵列。

接下来就是困扰你的线,我相信。首先,它需要来自&#39; ary&#39;数组通过RARRAY_AREF宏。其次,它通过rb_yield将元素的值传递给给定的块(即&#39; a + 1&#39;)。因此,它不存储任何东西。

rb_yield(RARRAY_AREF(ary, i));

由于在rb_yield中没有写入任何内容,因此该函数会返回&#39; ary&#39; [见上文]的数组是输入&#39;数组&#39;。

将其与地图进行比较!&#39;可以帮助你进一步:

static VALUE rb_ary_collect_bang(VALUE ary)
{
    long i;

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

注意&#39; rb_ary_store&#39; &#39; for&#39;内的函数调用环。这是事情! rb_yield-s就像在每个&#39;变体,但它不会丢弃返回的结果。结果存储在我们[心爱的]&#39; ary的第i个元素中。阵列。

相关问题