Daniel
Daniel

Reputation: 33

Cannot grasp "borrowed value does not live long enough", please explain

Here is segment I've a problem with, basically just pushing a &str to Vec<&str> in the loop

fn main() {
    let mut accounting = vec!["Alice", "Ben"];
    
    loop {
        let mut add_input = String::from("");

        io::stdin()
            .read_line(&mut add_input)
            .expect("Failed to read line");

        let add_vec: Vec<&str> = add_input.trim()[..].split_whitespace().collect();

        if add_vec.len() < 1 {
            println!("Incorrect input, try again");
            continue;
        }

        let person = add_vec[0];
        accounting.push(person);
    }
}

let add_vec: Vec<&str> = add_input.trim()[..].split_whitespace().collect(); - here's where I get "borrowed value does not live long enough".

I was able to make my code work by changing target vector signature from Vec<&str> to Vec<String> and pushing not a &str but &str.to_string()

I understand that pushing a &str bacibally making it invalid to for the scope that .push was called in, but while that is happening right at the end of the loop - why is that a problem?

The error give is:

$ rustc main.rs
error[E0597]: `add_input` does not live long enough
  --> main.rs:14:34
   |
14 |         let add_vec: Vec<&str> = add_input.trim()[..].split_whitespace().collect();
   |                                  ^^^^^^^^^^^^^^^^ borrowed value does not live long enough
...
22 |         accounting.push(person);
   |         ----------------------- borrow later used here
23 |     }
   |     - `add_input` dropped here while still borrowed

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.

Upvotes: 3

Views: 520

Answers (1)

Toerktumlare
Toerktumlare

Reputation: 14820

first you create i vec in you main method. It will have the lifetime of the brackets surrounding the `main function.

fn main {
    // accounting has a lifetime between these 2 brackets.
    let mut accounting = vec!["Alice", "Ben"];
}

Later you create a new vec containing references inside the loop.

fn main {
    loop {
        // add_vec has a lifetime between the loop brackets
        let add_vec: Vec<&str> = add_input.trim()[..].split_whitespace().collect();
    }
}

That vec has lifetime between the loop bracket. Since that vec contains &str it only contains references to slices of strings that are most likely stored on the stack that is accessible between the loop brackets.

Later in your code you want to add this vec of &str to the outer vec. Its here we will get a problem. The problem is that when we exit the loop the str will get dropped, and what is left will be a vec with a lot of references that are not referencing something.

Hence your error:

borrowed value does not live long enough

The borrowed value (&str) between the loop brackets wont live long enough to be stored outside the brackets.

fn main {
    loop {
        // If you create something on the stack between these brackets

    } <--- it will get dropped here
}

So one solution here is if you want to design your code this way is that you instead from using &str switch to using String which will allocate memory on the heap for the string instead. This means the string won't get dropped when we exit the loop brackets.

But remember by allocating memory like that your program will consume more memory which is not always feasible (if you are in a memory constrained platform like for instance embedded)

Upvotes: 2

Related Questions