2016-02-11 13 views
7

Oggi mi sono imbattuto in uno strano comportamento di cessione elemento Array:strano comportamento di assegnazione elemento Array

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

Questo ha senso, però:

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

So che in [0,0] il primo zero è index e il secondo è il numero di elementi da effettuare in quell'array a partire da index.

Nei miei pensieri dovrebbe essere lo stesso del unshift, ma non lo è.

Qualcuno può spiegare il comportamento?

+1

Perché pensi che '[]' dovrebbe funzionare allo stesso modo come 'unshift'? Sono metodi diversi. – sawa

+0

@sawa hai ragione, era solo una cosa, ma puoi spiegare [0,0] comportamento. È abbastanza diverso – ImranNaqvi

+0

Credo che il documento per [Array # [\] =] (http://ruby-doc.org/core-2.2.0/Array.html#method-i-5B-5D-3D) sia piuttosto clear: "' ary [start, length] = obj' ... sostituisce un sottoarray [con gli elementi di 'obj'] dall'indice' start' per 'length' elements". Qui potresti trovare più chiaro scrivere 'arr.insert (0, arr2)'. (Se si desidera inserire "arr2" alla fine di "arr", è possibile scrivere "arr [arr.size, 0] = arr2' o" arr.insert (arr.size, * arr2) '). Notare il parallelo con [str \ [fixnum, fixnum \] = new_str] (http://ruby-doc.org/core-2.2.0/String.html#method-i-5B-5D-3D). –

risposta

2

Se dive into the ruby source code, troveremo una funzione denominata chiamata quando array assignment happens con tre argomenti (ad esempio indice, la lunghezza e nuovo valore):

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

E se seguiamo avanti nel rb_ary_splice faremo capita su dove avviene la magia:

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

in primo luogo si fa spazio nella matrice per i nuovi elementi e aggiorna la lunghezza:

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

Poi attraverso la magia di C puntatori, si inserisce il nuovo elemento (s):

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