Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"does not live long enough" error in same function

Tags:

rust

I expected this code to work because all bindings are in the same scope:

fn main() {
    let mut foobar = vec!["foo"];
    let bar = "bar".to_string();
    foobar.push(&bar);
}

But I am getting this error:

error: `bar` does not live long enough
 --> baz.rs:4:18
  |>
4 |>     foobar.push(&bar);
  |>                  ^^^
note: reference must be valid for the block suffix following statement 0 at 2:33...
 --> baz.rs:2:34
  |>
2 |>     let mut foobar = vec!["foo"];
  |>                                  ^
note: ...but borrowed value is only valid for the block suffix following statement 1 at 3:32
 --> baz.rs:3:33
  |>
3 |>     let bar = "bar".to_string();
  |>                                 ^

error: aborting due to previous error
like image 315
tshepang Avatar asked Jun 24 '16 23:06

tshepang


1 Answers

Variables declared in the same block are dropped in the reverse order that they are declared. In your code, bar is dropped before foobar:

fn main() {
    let mut foobar = vec!["foo"]; // <---------| 0
    let bar = "bar".to_string();  // <--| 1    |
    foobar.push(&bar);            //    | bar  | foobar
                                  // <--|      |
                                  // <---------|
    // In the error message
    // 0 is called "block suffix following statement 0", and
    // 1 is called "block suffix following statement 1"
}

You are pushing a reference to bar in foobar, so you have to ensure that bar lives at least as long as foobar. But because bar is declared after foobar, bar's lifetime is actually shorter than foobar's, which means that foobar contains a dangling reference for a short moment.

To make the code compile, declare bar before foobar:

fn main() {
    let bar = "bar".to_string();
    let mut foobar = vec!["foo"];
    foobar.push(&bar);
}

or opt in to non-lexical lifetimes:

#![feature(nll)]

fn main() {
    let mut foobar = vec!["foo"];
    let bar = "bar".to_string();
    foobar.push(&bar);
}

Although this still has a dangling reference, it doesn't matter because dropping a reference does nothing; the Vec doesn't need to use the value of the references it contains when it's dropped.

like image 160
malbarbo Avatar answered Nov 19 '22 18:11

malbarbo