Vector of references

I have a vector of strings (String). I want to call a method,
but the method requires a vector of string references (&Vec<&str>).
Is this impossible in Rust? No matter what I try, when I attempt to put the
references in a new vec created for this purpose, I get the common complaint:

 vec_sref.push(&text_elem);
  					 ^^^^^^^ borrowed value does not live long enough

Now, I know how to create a vec of string references, it's easy:
let vec_xrf: Vec<&str> = vec!["asgfdbc", "xyzwotf", "qwertya", "uwtsdbn", "uoeqdbf",
"zzxxdbc", "oipuytf", "seyodum", "ieiytfa", "evyrtqa"];

...but I can't hard-code the values in my case. The content is dynamic; it isn't predictable.
Is it possible to create a vec of references from a vec of regular Strings?

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=599ebd48e400c5db67d7a668272734a3

To store somewhere a reference, you have to store the value it is referencing. So, directly for your question:

It is possible, but only if you ensure that the original vector will be alive and not mutated as long as the vector of references is here.

In fact, &str is mostly a type of string literals and function arguments, it's rare to see it anywhere else. If you have dynamically-constructed string, you usually want it either owned (i.e. String), or - if it can be in most cases just referenced from literal, but sometimes should be rebuit - cloned-on-write (Cow<'static, str>).

Yes, you can certainly create a vec of references from a vec of Strings, however as @Cerberuser says, the strings need to live long enough.

Does your loop currently look like this?

    let mut references: Vec<&str> = Vec::new();
    for string in strings {
        references.push(&string);
    }

That produces the error you're seeing above:

error[E0597]: `string` does not live long enough
  --> src/main.rs:9:25
   |
9  |         references.push(&string);
   |         ----------      ^^^^^^^ borrowed value does not live long enough
   |         |
   |         borrow later used here
10 |     }
   |     - `string` dropped here while still borrowed

The key is the last line, "string dropped here while still borrowed". Why is the string being dropped? It is because the for loop will consume whatever iterator is passed to it, so that the strings themselves can be accessed in the loop body, without having to go via a reference.

The issue here though is that you want a reference, and you don't want the original vector of strings to be consumed, so the answer is to use an iterator that doesn't end up consuming the original vec. The .iter() method will produce an iterator of references instead:

    let mut references: Vec<&str> = Vec::new();
    for reference in strings.iter() {
        references.push(reference);
    }

The iterator over references will still be consumed, but that's fine, it is only needed for this loop anyway, and the references themselves will be copied into the new vec.

Since building up a vec from an iterator is common, there's a method for that too:

    let references: Vec<&str> = strings.iter().collect();

This says, "collect the items from the iterator into a new vec". Since .iter() produces an iterator of string references, this works all by itself. Typically there would be a map or a filter or something before the collect, but using it like this is fine too.

Playground link

3 Likes

Thanks to everyone for all the assistance.
I'll implement the suggestions and this will help a lot.
Thanks again!