I'm trying to implement a structure that can be infinitely iterated. Think it like a natural number. I have a limitation: it can't implement Copy
trait because the structure contains a String
field.
I've also implemented an Iterable
trait and its only member fn next(&mut self) -> Option<Self::Item>
.
Currently, I have the following code to iterate over the first 10 items of my structure:
let mut counter = 0;
let mut game:Option<Game> = Game::new(¶m);
loop {
println!("{:?}", game);
game = g.next();
counter = counter + 1;
if counter > 10 { break; }
}
I'd like to give to users of my crate
the ability to iterate over my struct using for in
construction, like this:
for next_game in game {
println!("{:?}", next_game);
}
Is it possible at all? How can I achieve this? How to make my code better and what I have to do with my struct?
Iterator implementation:
pub struct Game {
/// The game hash
pub hash: Vec<u8>
}
impl Iterator for Game {
type Item = Game;
fn next(&mut self) -> Option<Self::Item> {
let mut hasher = Sha256::new();
hasher.input(&hex::encode(&self.hash)); // we need to convert the hash into string first
let result = hasher.result().to_vec();
Some(Game {
hash: result
})
}
}
Example: broken behavior with for
let mut game:Game = Game::new(&s).unwrap();
for g in game.take(2) {
println!("{}", g);
}
Now if we run example, we will get two Game
structs with same hash
, while expected behavior is that the first g
will have hash
equal to SHA256(game.hash) and the next g
's hash will be SHA256(SHA256(game.hash)). It works properly when I call .next()
.
In the Rust iterators actually can be divided into 2 categories. Iterators which own the struct, thus can be created using .into_iter()
which consumes self
.
And iterators that iterate over structure without consuming it. They can be created be usually created using: .iter
, .iter_mut()
For more information see related question: What is the difference between iter and into_iter? And documention: The three forms of iteration
To create iterator you should implement either IntoIterator
trait, which will transform your structure into iterator or write functions which will create iterator: iter_mut
, iter
pub fn iter_mut(&mut self) -> IterMut<T>
pub fn iter(&self) -> Iter<T>
So by convention you need 2 new types IterMut
and Iter
impl Iterator for Iter {
type Item = /* ... */;
fn next(&mut self) -> Option<Self::Item> {
/* ... */
}
}
impl Iterator for IterMut {
type Item = &mut /* ... */;
fn next(&mut self) -> Option<Self::Item> {
/* ... */
}
}
They usually contain in them reference to the parent structure. For example for linked list it can be current node (which is updated every iteration). For array-like structures it can be index and reference to the parent, so index will incremented every time and element accessed using index operator and etc..
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With