I have a trait
pub trait Reducer {
type Item;
fn reduce_all(&self) -> Self::Item
}
I have a concrete type
struct Counter {
amount: u32
}
I've implemented Reducer
for Vec<Counter>
like so:
impl<T: Borrow<Counter>> Reducer for Vec<T> {
type Item::Counter;
fn reduce_all(&self) -> Self::Item { ... implementation here ...}
}
Now I have a different concrete type
struct Statistic {
x_val: u32
}
and tried to also implement Reducer on Vec using the same technique:
impl<T: Borrow<SessionStat>> Reducer for Vec<T> {
...
but getting this error:
impl<T: Borrow<Counter>> Reducer for Vec<T> {
| ------------------------------------------- first implementation here
...
67 | impl<T: Borrow<SessionStat>> Reducer for Vec<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `std::vec::Vec<_>`
Not sure how to implement this trait twice for different vector contents
CodePudding user response:
Depending on your circumstances, you might not want Item
to be an associated type but rather have your Reducer
trait be generic over the type it returns. This would allow you to make a collection "reducible" to lots of types instead of just one and it would disambiguate which implementation to use, given the type of the collection and what it's supposed to reduce to. C.f. The Book and this answer regarding the difference between generic traits and associated types.
Your implementation might then look something like this:
use std::borrow::Borrow;
pub trait Reducer<I> {
// ----------^^^
// make `Reducer` generic over the type it returns
// ---------------------v
fn reduce_all(&self) -> I;
}
struct Counter {
amount: u32,
}
impl<T: Borrow<Counter>> Reducer<Counter> for Vec<T> {
fn reduce_all(&self) -> Counter {
todo!()
}
}
struct SessionStat {
x_val: u32,
}
impl<T: Borrow<SessionStat>> Reducer<SessionStat> for Vec<T> {
fn reduce_all(&self) -> SessionStat {
todo!()
}
}
CodePudding user response:
Because your trait is not generic, so you can only implement it once. If you want to implement the trait multiple type you have to make it generic. The thing is is that you use associated types, so you have to get rid of it and make your trait like this:
pub trait Reducer<T> {
fn reduce_all(&self) -> T
}
then you can do
impl<T: Borrow<Counter>> Reducer<Counter> for Vec<T> {
fn reduce_all(&self) -> Counter { ... implementation here ...}
}
impl<T: Borrow<SessionStat>> Reducer<SessionStat> for Vec<T> {
...
}
Edit:
looking at it there is a possibility for you to keep the trait the original way by creating a new trait and do something like this:
you create a trait that mark the type as reducible:
pub trait Reducible {
fn foo(self, &mut Self);
// reduce self into another self, or whatever you are doing
// you get the point
}
then implement the trait for Vec only once:
impl<T: Reducible, B: Borrow<T>> Reducer for Vec<B> {
type Item = T; // you then now keep the associated type !
fn reduce_all(&self) -> T { ... implementation here ...}
}
so this way it's the Reducible trait that does most of the work.