【问题标题】:Strange behaviour of Array element assignment数组元素分配的奇怪行为
【发布时间】:2016-05-22 16:33:42
【问题描述】:

今天遇到了Array元素赋值的一些奇怪行为:

arr = ["a","b"]
arr2 = [1,2]
arr.unshift(arr2) #= [[1, 2], "a", "b"] 
arr.push(arr2) #=> ["a", "b", [1, 2]] 

这是有道理的,但是:

arr[0,0] = arr2 #=> [1, 2, "a", "b"] 

我知道在[0,0] 中,第一个零是index,第二个是从index 开始的数组中要影响的元素数。

在我看来,它应该与unshift 相同,但事实并非如此。

谁能解释一下这种行为?

【问题讨论】:

  • 为什么你认为[] 应该以与unshift 相同的方式工作?它们是不同的方法。
  • @sawa 你说得对,那只是一件事,但你能解释一下 [0,0] 的行为吗?完全不同
  • 我相信Array#[]= 的文档非常清楚:“ary[start, length] = obj...从start 元素的start 索引中替换一个子数组[使用obj 的元素] ”。在这里你可能会发现写arr.insert(0,arr2)更清楚。 (如果你想在arr的末尾插入arr2,你可以写arr[arr.size,0] = arr2arr.insert(arr.size, *arr2))。注意与str[fixnum, fixnum] = new_str 的相似之处。

标签: arrays ruby ruby-on-rails-4


【解决方案1】:

如果我们dive into the ruby source code,我们会找到一个名为rb_ary_splice 的函数,当array assignment happens 使用三个参数(即索引、长​​度和新值)时调用:

static VALUE
rb_ary_aset(int argc, VALUE *argv, VALUE ary)
{
    long offset, beg, len;

    if (argc == 3) {
        rb_ary_modify_check(ary);
        beg = NUM2LONG(argv[0]);
        len = NUM2LONG(argv[1]);
        rb_ary_splice(ary, beg, len, argv[2]);
        return argv[2];
    }
[...]

如果我们继续关注rb_ary_splice,我们就会发现奇迹发生的地方:

static void
rb_ary_splice(VALUE ary, long beg, long len, VALUE rpl)
{
    long rlen;
    long olen;

    if (len < 0) rb_raise(rb_eIndexError, "negative length (%ld)", len);
    olen = RARRAY_LEN(ary);

    [...]

        if (len != rlen) {
            RARRAY_PTR_USE(ary, ptr,
                   MEMMOVE(ptr + beg + rlen, ptr + beg + len,
                       VALUE, olen - (beg + len)));
            ARY_SET_LEN(ary, alen);
        }
        if (rlen > 0) {
            MEMMOVE(RARRAY_PTR(ary) + beg, RARRAY_CONST_PTR(rpl), VALUE, rlen);
        }
    }
    RB_GC_GUARD(rpl);
}

首先它在数组中为新元素腾出空间并更新长度:

RARRAY_PTR_USE(ary, ptr,
    MEMMOVE(ptr + beg + rlen, ptr + beg + len,
        VALUE, olen - (beg + len)));
ARY_SET_LEN(ary, alen);

然后通过 C 指针的魔力,插入新元素:

MEMMOVE(RARRAY_PTR(ary) + beg, RARRAY_CONST_PTR(rpl), VALUE, rlen);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-30
    • 1970-01-01
    • 2014-05-18
    相关资源
    最近更新 更多