Итератор — это поведенческий паттерн, позволяющий последовательно обходить сложную коллекцию, без раскрытия деталей её реализации.
Благодаря Итератору, клиент может обходить разные коллекции одним и тем же способом, используя единый интерфейс итераторов.
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