Reputation: 397
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?
Upvotes: 10
Views: 621
Reputation: 65692
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!()
}
}
Upvotes: 7