4

In my struct I have a from function that takes a shared reference to a vector of elements of type T and does some initialisation.

fn from(t: &Vec<T>) -> () {
    // ...
    for a in t {
        // ...
    }
    for a in t {
        // ...
    }
}

I also have another function from_partial that first performs some filtering on &Vec<T> and wants to pass this reduced list of elements to from. I don't want to clone so from_partial constructs the vector as Vec<&T> instead of Vec<T>. I also don't want to duplicate the logic in from as all in needs to do is loop over the vector and get a &T to store somewhere.

In my concrete type example, I can assign both &Vec<&Bar> and &Vec<Bar> to from

let a: &Vec<&Bar> = &test.iter().collect();
let b: &Vec<Bar> = test;
Foo::from(a); // can assign &Vec<&Bar>
Foo::from(b); // can assign &Vec<Bar>

However when working with generic types, I am unable to do so:

fn from_partial(t: &Vec<T>) -> () {
    // Here a function is called that does some filtering on &Vec<T>
    // and returns &Vec<&T>, but omitting for brevity.
    let example: &Vec<&T> = &t.iter().collect();
    Self::from(example); // cannot assign &Vec<&T> to &Vec<T>?
}

Here's the MVCE (Playground):

struct Foo<T> {
    t: T,
}
struct Bar {}

impl<T> Foo<T> {
    fn from(t: &Vec<T>) -> () {
        let mut v = Vec::new();
        for a in t {
            // ...
            v.push(Foo { t: a })
        }
        for a in t {
            // ...
            v.get(0);
        }
    }

    fn from_partial(t: &Vec<T>) -> () {
        // Here a function is called that does some filtering on &Vec<T>
        // and returns &Vec<&T>, but omitting for brevity.
        let example: &Vec<&T> = &t.iter().collect();
        Self::from(example); // cannot assign &Vec<&T> to &Vec<T>?
    }
}

fn main() {}

fn test(test: &Vec<Bar>) {
    let a: &Vec<&Bar> = &test.iter().collect();
    let b: &Vec<Bar> = test;
    Foo::from(a); // can assign &Vec<&Bar>
    Foo::from(b); // can assign &Vec<Bar>
}

Is there any sort of constraint I can add on T that would make this possible? To essentially prevent me from duplicating exactly the same logic in from twice.

ᴘᴀɴᴀʏɪᴏᴛɪs
  • 7,169
  • 9
  • 50
  • 81
  • Related Q&A: [How to write a function that accepts a `Vec` of borrowed or owned elements?](/q/73839107/2189130) which answers the title more directly since he issue here was a simple misapplication of generic types. – kmdreko Sep 24 '22 at 19:29

1 Answers1

5

You need to replace Self::from(example); with Foo::from(example);.

Consider that T is Bar, then your from_partial call takes &Vec<Bar>. The issue is that Self then represents Foo::<Bar>, but you're trying to call from with &Bar, i.e. you need Foo::<&Bar>.

fn from_partial(t: &Vec<T>) -> () {
    let example: &Vec<&T> = &t.iter().collect();
    Foo::from(example);
}
vallentin
  • 23,478
  • 6
  • 59
  • 81