Aren't slice of structs and slice of refs equivalent as fn parameters?

This something that bothered me more than once. Consider this code:

    struct MyStruct{};

    fn do_something(data: &[MyStruct]) {
       // something useful here
    }

    fn main() {
       let objects = vec![MyStruct{}, MyStruct{}];
       do_something(&objects);  // <-- THIS IS OK;

       // but what happens if I have a vec of refs? Couldn't it work the same?
       let refs = vec![&MyStruct{}, &MyStruct{}];
       do_something(&refs);  // <-- THIS DOES NOT COMPILE;
    }

If I change the signature of do_something to do_something(data: &[&MyStruct]), then it compiles with &refs but not with &objects.
Anyway, from the point of view of the do_something function, it seems to me that there is no difference between &[MyStruct] and &[&MyStruct], so, couldn't it just accept both?

What is the simplest signature for a function that would accept both the slices transparently?

To accept both, you need the function to be generic. You can do that like this:

use std::borrow::Borrow;

fn do_something<T: Borrow<MyStruct>>(data: &[T]) {
   // something useful here
}

As for whether there is no difference between them, there is definitely a difference. They are represented in two quite different ways in memory, and the assembly required for each would be different.

8 Likes

@alice
Ok, it makes sense. So the difference is really a technical one and the reasoning is the same of the case in which the parameter is a trait.
Thank you!

Would someone need it, this is another signature that accepts what requested:

fn do_something<'a, T: IntoIterator<Iter = &'a MyStruct>>(data: T) {
   let data_iter = data.into_iter();
   // something useful here
}

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.