如何在Rust中正确实现Iterable结构?

时间:2019-01-26 15:35:02

标签: rust iterator

我正在尝试实现可以​​无限迭代的结构。认为它是自然数。我有一个局限性:它不能实现Copy特征,因为该结构包含一个String字段。

我还实现了Iterable特征及其唯一成员fn next(&mut self) -> Option<Self::Item>

当前,我有以下代码可以迭代结构的前10个项目:

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; }
}

我想让crate的用户能够使用for in构造对我的结构进行迭代,如下所示:

for next_game in game {
  println!("{:?}", next_game);
} 

有可能吗?我该如何实现?如何使我的代码更好,以及与我的结构有什么关系?

迭代器实现:

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
        })
    }
}

示例:for的行为不正确

let mut game:Game = Game::new(&s).unwrap();
for g in game.take(2) {
    println!("{}", g);
}

现在,如果我们运行示例,我们将获得两个具有相同Game的{​​{1}}结构,而预期的行为是第一个hash的{​​{1}}等于SHA256( game.hash),下一个g的哈希将为SHA256(SHA256(game.hash))。当我打电话给hash时,它可以正常工作。

1 个答案:

答案 0 :(得分:1)

在Rust中,迭代器实际上可以分为2类。因此,可以使用消耗.into_iter()的{​​{1}}创建拥有该结构的迭代器。

以及在不消耗结构的情况下迭代结构的迭代器。通常可以使用self.iter

创建它们

有关更多信息,请参见相关问题:What is the difference between iter and into_iter? 和记录:The three forms of iteration

要创建迭代器,您应该实现.iter_mut()特性,它将把结构转换成迭代器,或者编写函数来创建迭代器:IntoIteratoriter_mut

iter

pub fn iter_mut(&mut self) -> IterMut<T>

因此,按照惯例,您需要2种新类型pub fn iter(&self) -> Iter<T>IterMut

Iter

它们通常包含对父结构的引用。例如,对于链表,它可以是当前节点(每次迭代都会更新)。对于类似数组的结构,它可以是索引,也可以是对父结构的引用,因此,每次使用索引运算符等访问元素时,索引都会递增。