如何编写一个通用迭代器来保持状态并返回值而不使用克隆?

Ham*_*riZ 1 generics iterator clone rust

我尝试编写一个通用迭代器,但我不知道如何在不使用clone. 有什么方法可以在函数中创建变量next并返回引用吗?如果我替换Tu32,那么我可以只返回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"),
    }
}
Run Code Online (Sandbox Code Playgroud)

E_n*_*ate 5

一方面...不,您不能使迭代器返回对计数器值的引用。该Iterator::next()方法返回一个与接收者值没有生命周期连接的值&mut self,因此我们无法控制将在那里返回的引用的生命周期。这是必需的,因为当该值被该引用借用时我们无法修改该值。这个问题在另一个问题中得到了更好的解释中得到了更好的解释。

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

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

这只是因为u32implements的情况Copy,这意味着只要有必要它就会被复制。类型实现Copy也实现Clone,它会做与副本几乎相同的事情,这会发生在非泛型上下文中。

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

除此之外,您可以为Ton添加约束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())
    }
}
Run Code Online (Sandbox Code Playgroud)

也可以看看:

  • 另一种选择是要求“T: Copy”而不是“T: Clone”,这将允许使用“Some(self.count)”作为返回值。这样做实际上没有任何好处——它只会通过进一步限制“T”来使代码不那么通用——但它说明了与“u32”情况的相似之处。 (2认同)