0

I am trying to extend the functionality of the Iterator trait.

My statistics/iter_statistics.rs:

mod iter_statistics {
    pub trait IterStatistics: Iterator<Item = f64> {
        fn foo(&mut self) -> f64 {
            0.0
        }
    }

    impl IterStatistics for Iterator<Item = f64> {}
}

And statistics/mod.rs:

pub use self::iter_statistics::*;
mod iter_statistics;

And finally in my test code I have

use statistics::IterStatistics;

fn main() {
    let z: Vec<f64> = vec![0.0, 3.0, -2.0];
    assert_eq!(z.into_iter().foo(), 0.0);
}

When I run the test, I get:

error: no method name `foo` found for type `std::vec::IntoIter<f64>` in the current scope
assert_eq!(z.into_iter().foo(), 0.0);
                         ^~~

which is strange to me since the docs for IntoIter<T> say it implements Iterator<Item=T>.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
michael60612
  • 397
  • 2
  • 10
  • It's a side point, but as described you have a module `iter_statistics::iter_statistics`, which probably isn't what you meant; no need for the `mod {}` inside the file named after it. – Chris Emerson Oct 11 '16 at 07:04
  • @ChrisEmerson Yup that was a redundancy from when I was formulating the sample code :) – michael60612 Oct 11 '16 at 16:30

2 Answers2

6

The impl you have written will only apply to trait objects (e.g. &mut Iterator<Item=f64>), not for all types that implement Iterator<Item=f64>. You want to write a generic impl like this:

impl<T: Iterator<Item=f64>> IterStatistics for T {}
Francis Gagné
  • 60,274
  • 7
  • 180
  • 155
  • Related: [Why would I implement methods on a trait instead of as part of the trait?](http://stackoverflow.com/q/34438755/155423) – Shepmaster Oct 11 '16 at 01:36
3

Your implementation is backward. When programming in Rust, you have to forget about OO-inheritance and reason in terms of capabilities.

What does trait D: B means in Rust?

This means that D can only be implemented for types that already implement B. It's not inheritance, it's a constraint.

When to use trait D: B then?

The main reason to use this constraint is when you wish to provide a default implementation of D methods that will require associated items (traits, constants, methods) from B.

In general, you do not want to add more constraints than strictly necessary, as your clients may wish to use this trait in ways you did not foresee.

The one exception is when creating a trait as a "bundle of constraints", so that you do not have type T: SomeTrait + SomeOtherTrait + Send for all the methods your are implementing. This "bundle of constraints" should be empty, then; it's not a functional trait after all, just an "alias".

So, how to extend Iterator?

First declare a new trait:

pub trait IterStatistics {
    fn foo(&mut self) -> f64;
}

Then implement it for all types already implementing Iterator<Item = f64>:

impl<T> IterStatistics for T
    where T: Iterator<Item = f64>
{
    fn foo(&mut self) -> f64 {
        0.0
    }
}
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722