Array元素赋值的奇怪行为

时间:2022-06-15 21:36:57

Today I came across some strange behaviour of Array element assignment:

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

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

This makes sense, however:

然而,这是有道理的:

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

I know that in [0,0] the first zero is index and second is the number of elements to be effected in that array starting from index.

我知道在[0,0]中,第一个零是索引,第二个是从索引开始在该数组中生效的元素数。

In my thoughts it should be the same as the unshift, but it's not.

在我的想法中它应该与不移位相同,但事实并非如此。

Can any one explain the behavior?

任何人都可以解释这种行为吗?

1 个解决方案

#1


2  

If we dive into the ruby source code, we'll find a function named rb_ary_splice called when array assignment happens with three arguments (i.e. index, length, and new value):

如果我们深入研究ruby源代码,我们将找到一个名为rb_ary_splice的函数,当使用三个参数(即索引,长度和新值)进行数组赋值时调用它:

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];
    }
[...]

And if we follow along in rb_ary_splice we'll happen upon where the magic happens:

如果我们跟随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);
}

First it makes room in the array for the new elements and updates the length:

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

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

Then through the magic of C pointers, it inserts the new element(s):

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

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

#1


2  

If we dive into the ruby source code, we'll find a function named rb_ary_splice called when array assignment happens with three arguments (i.e. index, length, and new value):

如果我们深入研究ruby源代码,我们将找到一个名为rb_ary_splice的函数,当使用三个参数(即索引,长度和新值)进行数组赋值时调用它:

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];
    }
[...]

And if we follow along in rb_ary_splice we'll happen upon where the magic happens:

如果我们跟随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);
}

First it makes room in the array for the new elements and updates the length:

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

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

Then through the magic of C pointers, it inserts the new element(s):

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

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