![반복자](/images/patterns/cards/iterator-mini.png?id=76c28bb48f997b36965983dd2b41f02e)
러스트로 작성된 반복자
반복자는 복잡한 데이터 구조의 내부 세부 정보를 노출하지 않고 해당 구조를 차례대로 순회할 수 있도록 하는 행동 디자인 패턴입니다.
반복자 덕분에 클라이언트들은 단일 반복기 인터페이스를 사용하여 유사한 방식으로 다른 컬렉션들의 요소들을 탐색할 수 있습니다.
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