Search code examples
rustscopelifetime

How do Rust lifetimes interact with &str?


I'm just starting to learn Rust, and I tried typing down the following functions.

fn longest<'a>(a: &'a str, b: &'a str) -> &'a str{
    if a.len() > b.len() {
        a
    } else {
        b
    }
}

fn main() {
    let a = "hi";
    let c: &str;
    {
        let b = "nooooo";
        c = longest(a, b);
    }
    print!("{c}");
}

Why does the code compile and print "nooooo"? Shouldn't b's lifetime end in the inner scope, why can we still use c?


Solution

  • String literals has a 'static lifetime. It doesn't matter that b is dropped at the end of the inner scope, because value "nooooo" lives for the lifetime of the program (as it is stored in the binary itself). Problem will occur, when you for example allocate String on heap and then take a reference to it, which will have a shorter lifetime:

    fn longest<'a>(a: &'a str, b: &'a str) -> &'a str{
        if a.len() > b.len() {
            a
        } else {
            b
        }
    }
    
    fn main() {
        let a = "hi";
        let c: &str;
        {
            let b = String::from("nooooo");
            c = longest(a, &b);
        }
        print!("{c}");
    }
    

    This will fail to compile with the following error:

    error[E0597]: `b` does not live long enough
      --> src/main.rs:14:24
       |
    13 |         let b = String::from("nooooo");
       |             - binding `b` declared here
    14 |         c = longest(a, &b);
       |                        ^^ borrowed value does not live long enough
    15 |     }
       |     - `b` dropped here while still borrowed
    16 |     print!("{c}");
       |             --- borrow later used here