Barracuda
Barracuda

Reputation: 343

How to write a function that accepts a `Vec` of borrowed or owned elements?

In Rust, how can I pass a vector of owned objects to a function that expects a vector of borrowed objects? Is my only option to create a new vector?

What is the best practice for the signature of a function in which I care about the type of the contained generic of a struct but don't care about if it is borrowed or not?

Example situation:

fn using_vec_of_borrows(borrows: &Vec<&String>) {
    //...
}

fn main() {
    let foo: Vec<String> = Vec::new();
    using_vec_of_borrows(&foo);
}

How could I write using_vec_of_borrows() so that it accepts a vector of borrowed strings or a vector of owned strings? Or if it was part of an external library, could I convert my vector of owned strings to a vector of borrowed strings without iterating over it?

Keep in mind here that String is just used as an example type. It could be anything.

Upvotes: 2

Views: 1473

Answers (1)

kmdreko
kmdreko

Reputation: 60052

Quoting @trent from this answer:

When you hear "generic over references and non-references", think Borrow<T>.

Making your function generic over elements that implement Borrow<String> will allow it to accept both a &Vec<String> and &Vec<&String>:

use std::borrow::Borrow;

fn using_vec_of_borrows<T: Borrow<String>>(borrows: &[T]) {
    //...
}

fn main() {
    let foo: Vec<String> = Vec::new();
    using_vec_of_borrows(&foo);
    
    let foo: Vec<&String> = Vec::new();
    using_vec_of_borrows(&foo);
}

You can even change it to an iterator for more flexibility if the elements don't need to be contiguous.

Note: I changed the signature from &Vec<T> to &[T] since the latter is more idiomatic. And I would've changed Borrow<String> into Borrow<str> for a similar reason, but &String does not implement Borrow<str>.

See also:

Upvotes: 4

Related Questions