2016-01-03 10 views
8

Se provo a iterare su una fetta due volte, it works fine:Perché è possibile ripetere due volte una porzione, ma non un vettore?

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

Ma se provo a iterare su un vettore due volte, 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); 
} 

vedo che il tratto IntoIterator prende self da valore, quindi ha senso per me che il secondo esempio fallisce. Ma perché il primo esempio ha successo?

+1

pedantically, nel primo caso, il tipo di 'a' non è in realtà una fetta, è un riferimento ad un array di lunghezza 3. Tuttavia, * * coazioni Deref consentono un riferimento ad un array ad agire come una fetta nella maggior parte dei casi. – Shepmaster

+0

@Shepmaster grazie per aver chiarito. Ho ragione nel pensare che il tipo di 'a' nel primo esempio è' &[i32; 3] ', mentre una porzione sarebbe' & [i32] '? Inoltre, la deref coercizione che hai menzionato è visibile in [la lista qui] (https://doc.rust-lang.org/std/ops/trait.Deref.html), o è più magico? –

+1

Sì, quelli sarebbero i tipi. Ho mentito un po ', è un po' più magico di un dereferenziamento (https://github.com/rust-lang/rust/issues/29993), è una * coercizione *. I documenti verranno aggiornati presto con la correzione. – Shepmaster

risposta

12

Come hai detto tu, for opere prendendo la cosa hai chiesto a iterare, e passando attraverso IntoIterator::into_iter per produrre il valore iteratore reale. Inoltre, come hai detto, into_iter prende il soggetto in base al valore.

Così, quando si tenta di iterare su una Vector direttamente, questo significa che si passa l'intero vettore, per valore, nella sua IntoIterator realizzazione, consumando così il vettore nel processo. Ecco perché non è possibile eseguire iterazioni su un vettore direttamente due volte: iterandolo su di esso la prima volta che lo consuma, dopo di che non esiste più.

Tuttavia, le sezioni sono diverse: una sezione è un puntatore immutabile, preso in prestito ai suoi dati; puntatori immutabili e presi in prestito possono essere copiati liberamente. Ciò significa che il IntoIterator per le sezioni immutabili prende in prestito i dati e non li consuma (non che sia ). Oppure, per guardarlo in un altro modo, la sua implementazione IntoIterator sta semplicemente prendendo una copia della sezione, mentre non è possibile copiare uno Vec.

Va notato che si può iterare su una Vecsenza consumarlo entro l'iterazione di un prestito. Se controlli lo documentation for Vec, noterai che elenca le implementazioni di IntoIterator per Vec<T>, &Vec<T> e &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

Questo è stato super utile, grazie. Posso riassumerlo in questo modo? 1) Se un tipo deriva 'Copia', puoi passarlo attraverso una funzione" per valore "e usarlo ancora in seguito, e 2) in qualche modo magico, le fette implementano' Copia'. –

+2

@ JackO'Connor, è fondamentalmente corretto, eccetto che non c'è davvero nulla di magico in quelle slice che implementano 'Copia'. Una fetta è essenzialmente un riferimento immutabile e i riferimenti immutabili sono naturalmente "Copia". –

Problemi correlati