Iterator es un patrón de diseño de comportamiento que permite el recorrido secuencial por una estructura de datos compleja sin exponer sus detalles internos.
Gracias al patrón Iterator, los clientes pueden recorrer elementos de colecciones diferentes de un modo similar, utilizando una única interfaz iteradora.
Standard Iterator
Iterators are heavily used in idiomatic Rust code. This is how to use iterators over a standard array collection.
let array = &[1, 2, 3];
let iterator = array.iter();
// Traversal over each element of the vector.
iterator.for_each(|e| print!("{}, ", e));
Custom Iterator
In Rust, the recommended way to define your custom iterator is to use a standard Iterator
trait. The example doesn’t contain a synthetic iterator interface, because it is really recommended to use the idiomatic Rust way.
let users = UserCollection::new();
let mut iterator = users.iter();
iterator.next();
A next
method is the only Iterator
trait method which is mandatory to be implemented. It makes accessible a huge range of standard methods,
e.g. fold
, map
, for_each
.
impl Iterator for UserIterator<'_> {
fn next(&mut self) -> Option<Self::Item>;
}
users.rs: Collection & Iterator
pub struct UserCollection {
users: [&'static str; 3],
}
/// A custom collection contains an arbitrary user array under the hood.
impl UserCollection {
/// Returns a custom user collection.
pub fn new() -> Self {
Self {
users: ["Alice", "Bob", "Carl"],
}
}
/// Returns an iterator over a user collection.
///
/// The method name may be different, however, `iter` is used as a de facto
/// standard in a Rust naming convention.
pub fn iter(&self) -> UserIterator {
UserIterator {
index: 0,
user_collection: self,
}
}
}
/// UserIterator allows sequential traversal through a complex user collection
/// without exposing its internal details.
pub struct UserIterator<'a> {
index: usize,
user_collection: &'a UserCollection,
}
/// `Iterator` is a standard interface for dealing with iterators
/// from the Rust standard library.
impl Iterator for UserIterator<'_> {
type Item = &'static str;
/// A `next` method is the only `Iterator` trait method which is mandatory to be
/// implemented. It makes accessible a huge range of standard methods,
/// e.g. `fold`, `map`, `for_each`.
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.user_collection.users.len() {
let user = Some(self.user_collection.users[self.index]);
self.index += 1;
return user;
}
None
}
}
main.rs: Client code
use crate::users::UserCollection;
mod users;
fn main() {
print!("Iterators are widely used in the standard library: ");
let array = &[1, 2, 3];
let iterator = array.iter();
// Traversal over each element of the array.
iterator.for_each(|e| print!("{} ", e));
println!("\n\nLet's test our own iterator.\n");
let users = UserCollection::new();
let mut iterator = users.iter();
println!("1nd element: {:?}", iterator.next());
println!("2nd element: {:?}", iterator.next());
println!("3rd element: {:?}", iterator.next());
println!("4th element: {:?}", iterator.next());
print!("\nAll elements in user collection: ");
users.iter().for_each(|e| print!("{} ", e));
println!();
}
Output
Iterators are widely used in the standard library: 1 2 3
Let's test our own iterator.
1nd element: Some("Alice")
2nd element: Some("Bob")
3rd element: Some("Carl")
4th element: None
All elements in user collection: Alice Bob Carl