简体   繁体   中英

How do I write a generic iterator that keeps a state and returns a value without using clone?

I tried to write a generic iterator, but I do not see how to return value without using clone . Is there any way to create a variable within the next function and return a reference? If I replace T with u32 , then I can just return Some(self.count) , but using generics, it is not possible.

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

On the one hand... no, you cannot make the iterator return a reference to the counter's value. The Iterator::next() method returns a value which has no lifetime connection with the receiver value &mut self , so we cannot control the lifetime of the reference that would be returned there. This would be required because we cannot modify the value while it's borrowed by that reference. This concern is better explained in another question .

On the other hand , the real concern emerges here:

If I replace T with u32 , then I can just return Some(self.count) , but using generics, it is not possible.

This is only the case because u32 implements Copy , which means that it is copied around whenever it is necessary. Types implementing Copy also implement Clone , which would do just about the same thing as a copy, which would have happened in the non-generic context.

As such, the cloning operations that you have in this are reasonable, since you want to return the value of the counter while still owning its own state. When the T of that counter is a primitive integer such as u32 , the clone is as cheap as a copy of that integer.

Other than that, you can add a constraint for T on AddAssign<T> , so that you can use the += operator to increment the internal state.

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

See also:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM