Iteradores y Ownership (Propiedad)
El modelo de ownership de Rust afecta a muchas APIs. Un ejemplo serían los traits Iterator
y IntoIterator
.
Iterator
Los traits son como las interfaces: describen el comportamiento (métodos) de un tipo. El trait Iterator
indica que se puede llamar a next
hasta que se obtenga None
:
#![allow(unused)] fn main() { pub trait Iterator { type Item; fn next(&mut self) -> Option<Self::Item>; } }
Utiliza este trait de la siguiente forma:
fn main() { let v: Vec<i8> = vec![10, 20, 30]; let mut iter = v.iter(); println!("v[0]: {:?}", iter.next()); println!("v[1]: {:?}", iter.next()); println!("v[2]: {:?}", iter.next()); println!("No more items: {:?}", iter.next()); }
¿Qué tipo devuelve el iterador? Prueba tu respuesta aquí:
fn main() { let v: Vec<i8> = vec![10, 20, 30]; let mut iter = v.iter(); let v0: Option<..> = iter.next(); println!("v0: {v0:?}"); }
¿Por qué se usa este tipo?
IntoIterator
El trait Iterator
te indica cómo iterar una vez que has creado un iterador. El trait relacionado IntoIterator
indica cómo crear el iterador:
#![allow(unused)] fn main() { pub trait IntoIterator { type Item; type IntoIter: Iterator<Item = Self::Item>; fn into_iter(self) -> Self::IntoIter; } }
La sintaxis aquí significa que cada implementación de IntoIterator
debe declarar dos tipos:
Item
: el tipo sobre el que iteramos, comoi8
,IntoIter
: el tipoIterator
devuelto por el métodointo_iter
.
Ten en cuenta que IntoIter
y Item
están vinculados: el iterador debe tener el mismo tipo de Item
, lo que significa que devuelve Option<Item>
.
Al igual que antes, ¿qué tipo devuelve el iterador?
fn main() { let v: Vec<String> = vec![String::from("foo"), String::from("bar")]; let mut iter = v.into_iter(); let v0: Option<..> = iter.next(); println!("v0: {v0:?}"); }
Bucles for
Ahora que conocemos Iterator
e IntoIterator
, podemos crear bucles for
. Llaman a into_iter()
sobre una expresión e iteran sobre el iterador resultante:
fn main() { let v: Vec<String> = vec![String::from("foo"), String::from("bar")]; for word in &v { println!("word: {word}"); } for word in v { println!("word: {word}"); } }
¿Cuál es el tipo de word
en cada bucle?
Experimenta con el código anterior y consulta la documentación sobre impl IntoIterator for &Vec<T>
y sobre impl IntoIterator for Vec<T>
para comprobar las respuestas.