Penso che ci sia qualcosa da chiarire un po 'di più. I tipi di raccolta, come Vec<T>e VecDeque<T>, hanno un into_itermetodo che produce Tperché implementano IntoIterator<Item=T>. Non c'è nulla che ci impedisca di creare un tipo Foo<T>se è ripetuto, non produrrà Taltro tipo U. Cioè, Foo<T>implementa IntoIterator<Item=U>.
In effetti, ci sono alcuni esempi in std: &Path attrezzi IntoIterator<Item=&OsStr> e &UnixListener attrezzi IntoIterator<Item=Result<UnixStream>> .
La differenza tra into_itereiter
Torna alla domanda originale sulla differenza tra into_itere iter. Simile a quello che altri hanno sottolineato, la differenza è che into_iterè un metodo richiesto IntoIteratorche può produrre qualsiasi tipo specificato in IntoIterator::Item. Tipicamente, se un tipo implementa IntoIterator<Item=I>, per convenzione ha anche due metodi ad-hoc: itere iter_mutche producono &Ie &mut I, rispettivamente.
Ciò che implica è che possiamo creare una funzione che riceve un tipo che ha un into_itermetodo (cioè è un iterabile) usando un limite tratto:
fn process_iterable<I: IntoIterator>(iterable: I) {
for item in iterable {
// ...
}
}
Tuttavia, non possiamo * usare un tratto associato per richiedere che un tipo abbia un itermetodo o un iter_mutmetodo, perché sono solo convenzioni. Possiamo dire che into_iterè più ampiamente utilizzabile di itero iter_mut.
Alternative a itereiter_mut
Un altro interessante da osservare è che iternon è l'unico modo per ottenere un iteratore che cede &T. Per convenzione (di nuovo), i tipi di raccolta SomeCollection<T>in stdcui hanno itermetodo hanno anche i loro tipi di riferimento immutabili &SomeCollection<T>implementare IntoIterator<Item=&T>. Ad esempio, &Vec<T> implementa IntoIterator<Item=&T> , quindi ci consente di iterare su &Vec<T>:
let v = vec![1, 2];
// Below is equivalent to: `for item in v.iter() {`
for item in &v {
println!("{}", item);
}
Se v.iter()è equivalente a &vquello in entrambi gli strumenti IntoIterator<Item=&T>, perché Rust fornisce entrambi? È per l'ergonomia. Nei forloop, è un po 'più conciso da usare &vdi v.iter(); ma in altri casi, v.iter()è molto più chiaro di (&v).into_iter():
let v = vec![1, 2];
let a: Vec<i32> = v.iter().map(|x| x * x).collect();
// Although above and below are equivalent, above is a lot clearer than below.
let b: Vec<i32> = (&v).into_iter().map(|x| x * x).collect();
Allo stesso modo, in forloop, v.iter_mut()può essere sostituito con &mut v:
let mut v = vec![1, 2];
// Below is equivalent to: `for item in v.iter_mut() {`
for item in &mut v {
*item *= 2;
}
Quando fornire (implementare) into_itere itermetodi per un tipo
Se il tipo ha un solo "modo" su cui iterare, dovremmo implementare entrambi. Tuttavia, se ci sono due o più modi in cui può essere ripetuto, dovremmo invece fornire un metodo ad hoc per ciascun modo.
Ad esempio, Stringnon fornisce né into_iterné iterperché ci sono due modi per iterarlo: iterare la sua rappresentazione in byte o iterare la sua rappresentazione in caratteri. Fornisce invece due metodi: bytesper iterare i byte e charsper iterare i caratteri, in alternativa al itermetodo.
* Beh, tecnicamente possiamo farlo creando un tratto. Ma allora abbiamo bisogno di implquel tratto per ogni tipo che vogliamo usare. Nel frattempo, molti tipi stdgià implementano IntoIterator.