简体   繁体   中英

conflicting implementation for a trait on different contents of a vector

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

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!()
    }
}

Playground

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM