Restrict associated type of trait bound to make a difference iterator

I'm trying to make my own iterator of differences over another iterator. In keeping this generic I'm running into some issues. Here's what I have so far:

struct Differences<I: Iterator> {
    iter: I,
    last: Option<I::Item>,
}

impl<I> Iterator for Differences<I>
where
    I::Item: Sub,
    I: Iterator,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        match (self.iter.next(), self.last) {
            (None, _) => None,
            (Some(val), None) => {
                self.last = Some(val);
                self.next()
            }
            (Some(new), Some(last)) => {
                self.last = Some(new);
                Some(new - last)
            }
        }
    }
}

this is giving me an error:

error[E0308]: mismatched types
   --> src/bin/22.rs:71:22
    |
71  |                 Some(new - last)
    |                 ---- ^^^^^^^^^^ expected `std::iter::Iterator::Item`, found `std::ops::Sub::Output`
    |                 |
    |                 arguments to this enum variant are incorrect
    |
    = note: expected associated type `<I as Iterator>::Item`
               found associated type `<<I as Iterator>::Item as Sub>::Output`
    = note: an associated type was expected, but a different one was found
help: the type constructed contains `<<I as Iterator>::Item as Sub>::Output` due to the type of the argument passed
   --> src/bin/22.rs:71:17
    |
71  |                 Some(new - last)
    |                 ^^^^^----------^
    |                      |
    |                      this argument influences the type of `Some`
note: tuple variant defined here
   --> /home/andrew/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:580:5
    |
580 |     Some(#[stable(feature = "rust1", since = "1.0.0")] T),
    |     ^^^^

I understand that the Sub trait has an associated type of Output. I feel like there should be a way to add some more restrictions to make the type of Output equal to I but I don't know how to accomplish that.

1 Like
where
    I::Item: Copy + Sub<Output = I::Item>,
1 Like

Thanks, that works.

I just had a slightly different idea that is a little bit less restrictive:

impl<I> Iterator for Differences<I>
where
    I::Item: Copy + Sub,
    I: Iterator,
{
    type Item = <I::Item as Sub>::Output;

    fn next(&mut self) -> Option<Self::Item> {
        match (self.iter.next(), self.last) {
            (None, _) => None,
            (Some(val), None) => {
                self.last = Some(val);
                self.next()
            }
            (Some(new), Some(last)) => {
                self.last = Some(new);
                Some(new - last)
            }
        }
    }
}

This version doesn't require the Sub trait to return the same type as the iterator I'm pulling from. Useful for example if I wanted to iterate over durations between instants.

2 Likes