Avba
Avba

Reputation: 15266

How can I combine implementations of a trait for Vec<T> as well as Vec<&T>

I have a trait that I own:

trait Reducer {
  fn reduce(&self) -> Res;
}

I want to implement for the following cases:

struct MyStruct {... fields ...}

impl Reducer for Vec<MyStruct> {
  fn reduce(&self) -> Res { ... some implementation ... }
}

I want to get for as cheap as possible (not duplicating code etc.) for the refs of objects in Vec:

for instance:

// I want this please:

impl Reducer for Vec<&MyStruct> {
  // it's the same implementation as before
}

How should I change my impl signature to satisfy both cases?

Upvotes: 1

Views: 64

Answers (2)

isaactfa
isaactfa

Reputation: 6651

Using the Borrow trait you can generalize for all types that can be borrowed as a &MyStruct (which in particular includes MyStruct and &MyStruct):

use std::borrow::Borrow;

trait Reducer {
  fn reduce(&self) -> Res;
}

struct MyStruct;
struct Res;

impl<T: Borrow<MyStruct>> Reducer for Vec<T> {
    fn reduce(&self) -> Res {
        for t in self {
            let _t: &MyStruct = t.borrow();
            // do something with `_t`
        }
        Res
    }
}

fn main() {
    let v: Vec<MyStruct> = vec![];
    let v_ref: Vec<&MyStruct> = vec![];

    // fully qualified because it gets mangled with `Iterator::reduce` otherwise.
    Reducer::reduce(&v);
    Reducer::reduce(&v_ref);
}

Upvotes: 2

user4815162342
user4815162342

Reputation: 155046

If your reducer only needs to iterate over the items in the Vec, then there is no difference between Vec<T> and Vec<&T> because both can easily produce an iterator over &T. For example:

// actual implementation
fn reduce_it<'a>(_items: impl Iterator<Item = &'a MyStruct>) -> Res {
    todo!()
}

impl Reducer for Vec<MyStruct> {
    fn reduce(&self) -> Res {
        reduce_it(self.iter())
    }
}

impl Reducer for Vec<&MyStruct> {
    fn reduce(&self) -> Res {
        reduce_it(self.iter().copied())
    }
}

Playground

Upvotes: 1

Related Questions