10

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(&param);
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().

Vladimir Ignatev
  • 2,054
  • 1
  • 20
  • 34
  • What most people do is create a new struct, say `GameIter`, and provide it to the user like `game.iter()`. Any struct that implements `Iterator` can be used in a `for ... in ...` expression and if you want to limit the number of iterations, simply use `take`. – Caio Jan 26 '19 at 15:48
  • This question would be significantly clearer if you provided an implementation of the `Game` struct. – Andrey Tyukin Jan 26 '19 at 17:22
  • 1
    @AndreyTyukin: And of the `next` function... – Matthieu M. Jan 26 '19 at 17:29
  • 1
    What is wrong with implementing `Iterator` and `IntoIter`? – Matthieu M. Jan 26 '19 at 17:30
  • 2
    Related: [Writing an Iterator?](https://stackoverflow.com/questions/27601115/writing-an-iterator?noredirect=1&lq=1), [How to implement Iterator and IntoIterator for a simple struct?](https://stackoverflow.com/questions/30218886/how-to-implement-iterator-and-intoiterator-for-a-simple-struct/30220832) the answer is essentially in the question titles... – Andrey Tyukin Jan 26 '19 at 17:34
  • @AndreyTyukin I've just updated a question with the implementation of Iterator and better explanation of the problem I address in my question. – Vladimir Ignatev Jan 28 '19 at 05:55
  • All the question appeared because of a frustration that my implementation of Iterator works differently for `loop` and for `for`. The way my example with `loop` above works looks very same as described behavior of `for`, while I don't get expected behavior and can't catch what the problem with it, that's why I supposed that the problem is how I implement Iterator trait. – Vladimir Ignatev Jan 28 '19 at 06:11

1 Answers1

10

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..

Inline
  • 2,566
  • 1
  • 16
  • 32