2016-01-03 14 views
8

Gdy próbuję iteracyjne nad plasterek dwukrotnie it works fine:Dlaczego można iterować po plasterku dwa razy, ale nie wektor?

let a = &[1, 2, 3]; 
for i in a { 
    println!("{}", i); 
} 
for i in a {   // works fine 
    println!("{}", i); 
} 

Ale jeśli próbuję iteracyjne nad wektor dwukrotnie it fails:

let a = vec![1, 2, 3]; 
for i in a { 
    println!("{}", i); 
} 
for i in a {   // error: use of moved value: `a` 
    println!("{}", i); 
} 

widzę, że cecha IntoIterator trwa self przez wartość, więc ma sens, że drugi przykład zawodzi. Ale dlaczego pierwszy przykład się powiódł?

+1

pedantycznie, w pierwszym przypadku, typ 'A' nie jest rzeczywiście kawałek, to odniesienie do tablicy o długości 3. Jednakże * coercions deref * umożliwiają odniesienie do tablicy działać jak kawałek w większości przypadków. – Shepmaster

+0

@Shepmaster dzięki za wyjaśnienie. Czy mam rację, sądząc, że typem "a" w pierwszym przykładzie jest '&[i32; 3]', podczas gdy plasterek to '& [i32]'? Czy wymieniany przez Ciebie element deref jest widoczny na [liście] (https://doc.rust-lang.org/std/ops/trait.Deref.html), czy jest bardziej magiczny? –

+1

Tak, to byłyby typy. Kłamałem trochę, jest to [nieco bardziej magiczne niż dereferencji] (https://github.com/rust-lang/rust/issues/29993), to * przymus *. Dokumenty zostaną wkrótce zaktualizowane wraz z poprawką. – Shepmaster

Odpowiedz

12

Tak jak powiedziałeś, for prace biorąc rzecz poprosiłeś go iteracyjne nad i przepuszczenie go przez IntoIterator::into_iter produkować wartość iteratora rzeczywisty. Jak również powiedziałeś, into_iter pobiera temat według wartości.

Tak, podczas próby iteracyjne nad Vector bezpośrednio, to znaczy zdać cały wektor, wartością, do jego realizacji IntoIterator, więc zużywa wektora w procesie. Dlatego nie można iterować nad wektorem bezpośrednio dwa razy: iteracja nad nim po raz pierwszy pochłania go, po czym już nie istnieje.

Jednak plasterki są różne: plasterek to niezmienny, pożyczony wskaźnik do danych; niezmienne, pożyczone wskaźniki mogą być swobodnie kopiowane. Oznacza to, że IntoIterator dla niezmiennych plasterków po prostu pożycza dane i ich nie zużywa (nie, że może to być może być). Lub, patrząc na to w inny sposób, jego implementacja polega po prostu na skopiowaniu plasterka, podczas gdy nie można skopiować Vec.

Należy zauważyć, że można iterować po wartości Vec, nie używając, używając go do iteracji przez pożyczkę. Jeśli sprawdzisz numer documentation for Vec, zauważysz, że zawiera on implementacje IntoIterator dla Vec<T>, &Vec<T> i &mut Vec<T>.

let mut a: Vec<i32> = vec![1, 2, 3]; 

for i in &a {   // iterate immutably 
    let i: &i32 = i; // elements are immutable pointers 
    println!("{}", i); 
} 

for i in &mut a {  // iterate mutably 
    let i: &mut i32 = i;// elements are mutable pointers 
    *i *= 2; 
} 

for i in a {   // iterate by-value 
    let i: i32 = i;  // elements are values 
    println!("{}", i); 
} 

// `a` no longer exists; it was consumed by the previous loop. 
+0

To było bardzo pomocne, dzięki. Czy mogę to podsumować w ten sposób? 1) Jeśli typ pochodzi od 'Kopiuj', możesz przekazać go przez funkcję" według wartości "i nadal używać go później, i 2) w jakiś magiczny sposób, plastry implementują' Kopiuj'. –

+2

@ JackO'Connor, to w zasadzie poprawne, z wyjątkiem tego, że nie ma w tym nic naprawdę magicznego implementacji 'Copy'. Plasterek jest w zasadzie niezmiennym odniesieniem, a niezmienne odniesienia są naturalnie "Kopią". –

Powiązane problemy