我如何编写一个通用迭代器,该迭代器在不使用克隆的情况下保持状态并返回值?

时间:2019-02-22 21:53:39

标签: generics rust iterator clone

我试图编写一个通用的迭代器,但是如果不使用clone,我看不到如何返回值。有什么方法可以在next函数中创建变量并返回引用?如果我将T替换为u32,那么我只能返回Some(self.count),但是使用泛型是不可能的。

use num_traits::Num;
use std::clone::Clone;

struct Counter<T>
where
    T: Num + Clone,
{
    count: T,
}

impl<T> Counter<T>
where
    T: Num + Clone,
{
    fn new() -> Counter<T> {
        Counter { count: T::zero() }
    }
}

impl<T> Iterator for Counter<T>
where
    T: Num + Clone,
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        self.count = self.count.clone() + T::one();
        Some(self.count.clone())
    }
}

fn main() {
    let mut number: Counter<u32> = Counter::new();

    match number.next() {
        Some(x) => println!("Number {}", x),
        None => println!("Invalid"),
    }
}

1 个答案:

答案 0 :(得分:4)

一方面...不,您不能使迭代器返回对计数器值的引用。 Iterator::next()方法返回的值与接收者值&mut self没有生命周期的联系,因此我们无法控制在那里返回的引用的生命周期。这是必需的,因为当该引用借用该值时我们无法对其进行修改。在另一个question中可以更好地解释这种担忧。

另一方面,真正的担忧出现在这里:

  

如果我将T替换为u32,那么我只能返回Some(self.count),但是使用泛型是不可能的。

这是唯一的情况,因为u32实现了Copy,这意味着它在需要时被复制。实现Copy的类型也实现Clone,它的作用与非复制上下文中发生的复制几乎相同。

这样,您在其中进行的克隆操作是合理的,因为您希望在仍拥有其自身状态的同时返回计数器的值。当该计数器的T是诸如u32之类的原始整数时,该克隆副本的成本与该整数的副本一样便宜。

除此之外,您可以在T上为AddAssign<T>添加约束,以便可以使用+=运算符来递增内部状态。

impl<T> Iterator for Counter<T> where T: Num + Clone + AddAssign<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        self.count += T::one();
        Some(self.count.clone())
    }
}

另请参阅: