Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to implement a trait for iterators over all reference types generically?

Tags:

rust

I have a trait

trait Foo<T> : Iterator<Item=T> {
    fn bar(&mut self) -> f64;
}

I want to implement this trait once for a type T (in my case f64) over all its reference types (f64, &'a f64, and &'a mut f64) since logically it doesn't matter.

I currently have

impl<T: Iterator<Item = f64>> Foo<f64> for T {
    fn bar(&mut self) -> f64 {
        // duplicated code
    }
}

impl<'a, T: Iterator<Item = &'a f64>> Foo<&'a f64> for T {
    fn bar(&mut self) -> f64 {
        // duplicated code
    }
}

impl<'a, T: Iterator<Item = &'a mut f64>> Foo<&'a mut f64> for T {
    fn bar(&mut self) -> f64 {
        // duplicated code
    }
}

Is there a good way to accomplish this without duplication?

like image 238
michael60612 Avatar asked Oct 12 '16 02:10

michael60612


1 Answers

You can use the Borrow trait for this. If you look at the implementors in the documentation page, the first three are relevant here: it means that f64, &'a f64 and &'a mut f64 all implement Borrow<f64>. You'll have to call the borrow method on each value produced by the iterator to obtain a &f64.

use std::borrow::Borrow;

impl<T> Foo<T::Item> for T
    where T: Iterator,
          T::Item: Borrow<f64>
{
    fn bar(&mut self) -> f64 {
        unimplemented!()
    }
}

By the way, it doesn't really make sense to define a type parameter on the trait and at the same time put a constraint between that type parameter and a supertrait's associated type. A type T can only have one implementation of Iterator, therefore it can only have one implementation of Foo as well, despite the type parameter suggesting that it could implement many different Foo<T> traits. Therefore, the type parameter on Foo is completely redundant (you can just use the supertrait's associated types instead of the type parameter). Thus the code should look more like this:

use std::borrow::Borrow;

trait Foo: Iterator {
    fn bar(&mut self) -> f64;
}

impl<T> Foo for T
    where T: Iterator,
          T::Item: Borrow<f64>
{
    fn bar(&mut self) -> f64 {
        unimplemented!()
    }
}
like image 95
Francis Gagné Avatar answered Oct 24 '22 04:10

Francis Gagné