Creo que hay algo que aclarar un poco más. Los tipos de colección, como Vec<T>y VecDeque<T>, tienen un into_itermétodo que rinde Tporque se implementan IntoIterator<Item=T>. No hay nada que nos detenga para crear un tipo Foo<T>si se repite, no dará Tsino otro tipo U. Es decir, Foo<T>implementos IntoIterator<Item=U>.
De hecho, hay algunos ejemplos en std: &Path implementos IntoIterator<Item=&OsStr> e &UnixListener implementos IntoIterator<Item=Result<UnixStream>> .
La diferencia entre into_iteryiter
Volviendo a la pregunta original sobre la diferencia entre into_itery iter. Similar a lo que otros han señalado, la diferencia es que into_iteres un método requerido IntoIteratorque puede producir cualquier tipo especificado en IntoIterator::Item. Típicamente, si un tipo se implementa IntoIterator<Item=I>, por convención también tiene dos métodos ad-hoc: itery iter_mutque rinden &Iy &mut I, respectivamente.
Lo que implica es que podemos crear una función que recibe un tipo que tiene un into_itermétodo (es decir, es iterable) mediante el uso de un límite de rasgo:
fn process_iterable<I: IntoIterator>(iterable: I) {
for item in iterable {
// ...
}
}
Sin embargo, no podemos * usar un rasgo obligado a requerir que un tipo tenga un itermétodo o iter_mutmétodo, porque son solo convenciones. Podemos decir que into_iteres más ampliamente utilizable que itero iter_mut.
Alternativas a iteryiter_mut
Otro iteraspecto interesante para observar es que no es la única forma de obtener un iterador que rinda &T. Por convención (nuevamente), los tipos de colección SomeCollection<T>en los stdque tienen itermétodo también tienen &SomeCollection<T>implementados sus tipos de referencia inmutables IntoIterator<Item=&T>. Por ejemplo, &Vec<T> implementa IntoIterator<Item=&T> , por lo que nos permite iterar sobre &Vec<T>:
let v = vec![1, 2];
// Below is equivalent to: `for item in v.iter() {`
for item in &v {
println!("{}", item);
}
Si v.iter()es equivalente a &vque ambos implementos IntoIterator<Item=&T>, ¿por qué Rust proporciona ambos? Es para la ergonomía. En forbucles, es un poco más conciso de usar &vque v.iter(); pero en otros casos, v.iter()es mucho más claro 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();
Del mismo modo, en forbucles, v.iter_mut()se puede reemplazar 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;
}
Cuándo proporcionar (implementar) into_itery itermétodos para un tipo
Si el tipo solo tiene una "forma" para iterar, deberíamos implementar ambas. Sin embargo, si hay dos formas o más de que se puede repetir, deberíamos proporcionar un método ad-hoc para cada forma.
Por ejemplo, Stringno proporciona into_iterni iterporque hay dos formas de iterarlo: iterar su representación en bytes o iterar su representación en caracteres. En cambio, proporciona dos métodos: bytespara iterar los bytes y charspara iterar los caracteres, como alternativas al itermétodo.
* Bueno, técnicamente podemos hacerlo creando un rasgo. Pero entonces necesitamos implese rasgo para cada tipo que queremos usar. Mientras tanto, muchos tipos stdya se implementan IntoIterator.