Is there a way to implement a trait for iterators

2019-06-15 17:56发布

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?

标签: rust
1条回答
beautiful°
2楼-- · 2019-06-15 18:35

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!()
    }
}
查看更多
登录 后发表回答