&str seems to live longer than scope

Following code doesn't compile as told in Listing 10-24.

fn main() {
    let string1 = String::from("long string is long");
    let result;
    {
        let string2 = String::from("xyz");
        result = longest(string1.as_str(), string2.as_str());
    }
    println!("The longest string is {}", result);
}

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

But changing line 5 and 6 to following, compiles and works fine.

    let string2 = "xyz";
    result = longest(string1.as_str(), string2);

Though, string2 is out of scope now, the code still compiles and works fine. Through some experimentation, found out that when we're assigning String to string2, result has the reference of same string.
But when we assign &str to string2, result doesn't point to the same string.
I though maybe &str might be implementing Copy trait under the hood, but didn't find that in Docs. Also, I tried same setup with i32 (not &i32) without lifetime annotation, it worked as it implements Copy trait. But &str doesn't work without lifetime annotations, though behave like they implement Copy trait by being available after scope has ended.
Could somebody please explain, what exactly is happening here?

All shared (&) references implement Copy: reference - Rust

&i32 will work the same way: Rust Playground

In this case, string2 is &'static str, i.e. it can afford to live forever - even after the variable itself goes out of scope, the data is still here, so any derived references (such as the one provided by longest) are still valid.

4 Likes