Adam
Adam

Reputation: 712

Create references to rust strings in two separate vectors

I have a vector of input Strings and I'd like to create two vectors containing references, &str, to those strings. Here's a simplified version of what I'm trying (the input is replaced with a simple vector initialisation):

let colours = vec!["red".to_string(), "black".to_string(), "blue".to_string()];
let mut starts_with_b = Vec::new();
let mut ends_with_e = Vec::new();

for colour in colours {
    if colour.starts_with("b") {
        starts_with_b.push(&*colour);
    }
    if colour.ends_with("e") {
        ends_with_e.push(&*colour);
    }
}

println!("{:?}", starts_with_b);
println!("{:?}", ends_with_e);

This code produces the compiler error "'colour' does not live long enough". How can I resolve this problem?

I've seen that this problem does not exist if I start off with string references, &str:

let colours = vec!["red", "black", "blue"];
let mut starts_with_b = Vec::new();
let mut ends_with_e = Vec::new();

for colour in colours {
    if colour.starts_with("b") {
        starts_with_b.push(colour);
    }
    if colour.ends_with("e") {
        ends_with_e.push(colour);
    }
}

println!("{:?}", starts_with_b);
println!("{:?}", ends_with_e);

Upvotes: 3

Views: 116

Answers (2)

at54321
at54321

Reputation: 11708

The problem with your code comes from the fact the temporary colour variable is a moved String, which means it's very short-lived. In your starts_with_b and ends_with_e vectors you need to store references to the values in colours, which can easily be done by simply not moving the values in colours while iterating them. The easiest way to do that is by doing this:

for colour in &colours {

instead of this:

for colour in colours {

That way colour will be of type &String, instead of a (moved) String, so you can simply push colour directly.

Note that that way the types of starts_with_b and ends_with_e will be Vec<&String> and not Vec<&str>, as you asked for. I presume that won't be an issue for you, but if it is, you can easily make them Vec<&str> by simply calling push(&colour[..]) instead of push(colour).

Upvotes: 5

Riwen
Riwen

Reputation: 5190

You can use for loop on the reference of colours:

let colours = vec!["red".to_string(), "black".to_string(), "blue".to_string()];
let mut starts_with_b = Vec::new();
let mut ends_with_e = Vec::new();

for colour in &colours {
    if colour.starts_with("b") {
        starts_with_b.push(colour);
    }
    if colour.ends_with("e") {
        ends_with_e.push(colour);
    }
}

println!("{:?}", starts_with_b);
println!("{:?}", ends_with_e);

Upvotes: 1

Related Questions