1

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"),
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
HamoriZ
  • 2,370
  • 18
  • 38

1 Answers1

5

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:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
E_net4
  • 27,810
  • 13
  • 101
  • 139
  • 2
    Another option is to require `T: Copy` instead of `T: Clone`, which will allow to use `Some(self.count)` as the return value. There isn't really any advantage to doing so – it will only make the code less generic by further restricting `T` – but it illustrates the parallel to the `u32` case. – Sven Marnach Feb 23 '19 at 08:44