Je pense qu'il y a quelque chose à clarifier un peu plus. Les types de collection, tels que Vec<T>et VecDeque<T>, ont une into_iterméthode qui produit Tparce qu'ils implémentent IntoIterator<Item=T>. Rien ne nous empêche de créer un type Foo<T>si celui-ci est itéré, il ne donnera pas Tmais un autre type U. Autrement dit, des Foo<T>outils IntoIterator<Item=U>.
En fait, il existe quelques exemples dans std: les &Path outils IntoIterator<Item=&OsStr> et les &UnixListener outils IntoIterator<Item=Result<UnixStream>> .
La différence entre into_iteretiter
Revenons à la question initiale sur la différence entre into_iteret iter. Comme d'autres l'ont souligné, la différence est queinto_iter méthode requise IntoIteratorpeut donner n'importe quel type spécifié dans IntoIterator::Item. En règle générale, si un type implémente IntoIterator<Item=I>, par convention, il a également deux méthodes ad hoc: iteret iter_mutqui donnent &Iet &mut I, respectivement.
Ce que cela implique, c'est que nous pouvons créer une fonction qui reçoit un type qui a une into_iterméthode (c'est-à-dire qu'il s'agit d'un itérable) en utilisant un trait lié:
fn process_iterable<I: IntoIterator>(iterable: I) {
for item in iterable {
// ...
}
}
Cependant, nous ne pouvons pas * utiliser un trait lié pour exiger qu'un type ait une iterméthode ou une iter_mutméthode, car ce ne sont que des conventions. Nous pouvons dire que into_iterc'est plus largement utilisable que iterou iter_mut.
Alternatives à iteretiter_mut
Un autre intéressant à observer est que ce itern'est pas la seule façon d'obtenir un itérateur qui cède &T. Par convention (encore une fois), les types de collection SomeCollection<T>dans stdlesquels ont la iterméthode ont également leurs types de référence immuables &SomeCollection<T>implémentés IntoIterator<Item=&T>. Par exemple,&Vec<T> implements IntoIterator<Item=&T> , donc cela nous permet d'itérer sur &Vec<T>:
let v = vec![1, 2];
// Below is equivalent to: `for item in v.iter() {`
for item in &v {
println!("{}", item);
}
Si cela v.iter()équivaut à &vces deux implémentations IntoIterator<Item=&T>, pourquoi alors Rust fournit-il les deux? C'est pour l'ergonomie. Dansfor boucles, c'est un peu plus concis à utiliser &vque v.iter(); mais dans d'autres cas, v.iter()c'est beaucoup plus clair que (&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();
De même, dans for boucles, v.iter_mut()peut être remplacé par &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;
}
Quand fournir (implémenter) into_iteret iterméthodes pour un type
Si le type n'a qu'une seule «manière» d'être itérée, nous devons implémenter les deux. Cependant, s'il y a deux façons ou plus de l'itérer, nous devrions plutôt fournir une méthode ad hoc pour chaque façon.
Par exemple, Stringne fournit ni into_iterni itercar il existe deux façons de l'itérer: pour itérer sa représentation en octets ou pour itérer sa représentation en caractères. Au lieu de cela, il fournit deux méthodes: bytespour itérer les octets et charspour itérer les caractères, comme alternatives à la iterméthode.
* Eh bien, techniquement, nous pouvons le faire en créant un trait. Mais ensuite, nous avons besoin de implce trait pour chaque type que nous voulons utiliser. Pendant ce temps, de nombreux types sont stddéjà mis en œuvre IntoIterator.