How to properly implement Iterable structure in Rust? [duplicate]

╄→гoц情女王★ 提交于 2021-01-21 08:11:28

问题


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


回答1:


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



来源:https://stackoverflow.com/questions/54379841/how-to-properly-implement-iterable-structure-in-rust

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!