Search code examples
genericsrustiteratortraitsscoping

How do you extend a trait like itertools does with collect_vec()?


I would like to create a method similar to the collect_vec() function in itertools.

Creating a small example by copying the itertools code:

pub trait MyItertools: Iterator {
    fn collect_vec(self) -> Vec<Self::Item>
        where Self: Sized
    {
        self.collect()
    }
}

fn main() {
    let v = (0..5).collect_vec();
    println!("{:?}", v);
}

I rather naively expect that the compiler will use my collect_vec as MyItertools is in scope.

There must be some other magic that itertools is doing to get this to compile.

We get the error:

error[E0599]: no method named `collect_vec` found for struct `std::ops::Range<{integer}>` in the current scope
  --> src/main.rs:14:20
   |
14 |     let v = (0..5).collect_vec();
   |                    ^^^^^^^^^^^ method not found in `std::ops::Range<{integer}>`
   |
   = help: items from traits can only be used if the trait is implemented and in scope
note: `MyItertools` defines an item `collect_vec`, perhaps you need to implement it
  --> src/main.rs:5:1
   |
5  | pub trait MyItertools: Iterator {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error

Which is misleading as we have indeed implemented collect_vec in MyItertools.

One possible solution is to impl MyItertools for all flavours of Iterator, but there does not seem to be a way to do this for all Iterator implementing traits and types.


Solution

  • The missing magic piece of the puzzle is a generic blanket implementation that implements the MyItertools trait for all types which implement the Iterator trait. Updated fixed example:

    pub trait MyItertools: Iterator {
        fn collect_vec(self) -> Vec<Self::Item>
            where Self: Sized
        {
            self.collect()
        }
    }
    
    impl<T> MyItertools for T where T: Iterator {}
    
    fn main() {
        let v = (0..5).collect_vec();
        println!("{:?}", v);
    }
    

    playground