ProgrammingRust Developer / Backend Developer

Explain how iterators and iterator adaptors work in Rust. What is the difference between implementing a custom iterator and using standard adaptors, and in what cases should you implement your own iterator?

Pass interviews with Hintsage AI assistant

Answer

In Rust, the entire standard collection library is built on the concept of iterators. An iterator is an object that implements the Iterator trait, which defines the next() method. This method returns the next item in the data sequence (Option<T>, where Some(T) is the next value, and None signifies the end of the sequence).

Example of a standard iterator:

let v = vec![1, 2, 3]; let mut iter = v.iter(); while let Some(x) = iter.next() { println!("{}", x); }

Iterator adaptors are methods (like .map(), .filter(), .enumerate(), .take()) that return new iterators that process values "on the fly" according to provided functions.

Custom iterators are implemented by creating a structure and implementing the Iterator trait for it with custom behavior:

struct Counter { count: u8 } impl Iterator for Counter { type Item = u8; fn next(&mut self) -> Option<Self::Item> { if self.count < 5 { self.count += 1; Some(self.count) } else { None } } }

Use standard adaptors when they are sufficient for processing collections. Implementing a custom iterator is necessary if:

  • You need to represent an algorithmically generated/lazy sequence.
  • You require deep control over the process.
  • You need to integrate with external/non-standard data sources.

Trick Question

Can you create infinite iterators? What would happen if you tried to collect them into a collection, for example, using .collect()?

Answer: Yes, in Rust there are iterators like std::iter::repeat, which return an infinite sequence:

let mut endless = std::iter::repeat(1); endless.next(); // will return Some(1) indefinitely

If you try to collect such an iterator into a collection using .collect(), the program will hang or crash with a memory overflow because the iteration will not terminate on its own!

Examples of real errors due to lack of knowledge of the topic.


Story

In a REST API project, an array of 1000 elements was sorted, and then .iter().filter(|x| *x > 500) was used, but instead of .collect::<Vec<_>>(), they applied .fold(0, |acc, _| acc + 1) inside a complex adaptor, losing the understanding of whether the iteration would complete correctly. The result: random hangs due to the filtering occurring on an unrestricted lazy iterator with an internal error.


Story

In a proprietary engine for generating unique IDs, a random developer decided to implement their own iterator, forgetting to return None when reaching the limit. As a result, the iteration went into an infinite loop, the production server consumed all CPU and did not respond to requests.


Story

In the frontend part (WebAssembly module), an iterator with nested adaptors: .map().filter().skip() was used, and they tried to obtain the result through .collect() for a form. When changing the type under the adaptor, Rust produced a complex compile-time error about type mismatches because they forgot to specify the exact type of the collection: .collect::<Vec<_>>(). The problem was solved by adding an annotation, but they spent several hours searching for the cause.