Help understanding a lifetime behavior

Hi all!

I am studying the lifetime functionality in Rust following the 'The Rust Programming Language' book. In the chapter 10 the lifetime is explained and some examples are given. Then the writer suggests try to image another scenarios and see what happens and this is how I came to the behavior bellow:

//The function
fn longest<'a>(str1: &'a str, str2: &'a str) -> &'a str {
    if str1.len() > str2.len(){
        str1
    } else {
        str2
    }
}

fn main() {
    let str1 = String::from("Holy teeeest!");
    let result;

    {
        let another_str = "Inner str from scope.";
        result = longest(str1.as_str(), another_str);
    }
    println!("The longest str is {}", result);
}

The code above compiles and run, but the code bellow don't.

fn main() {
    let str1 = String::from("Holy test again!");
    let result;

    {
        let another_str = String::from("Inner str from scope.").as_str();
        result = longest(str1.as_str(), another_str);
    }
    println!("The longest str is {}", result);
}

The only diference from the first block to the second is the declaration of the another_str in the inner scope and the compiler shows the following message:

error[E0597]: `another_str` does not live long enough
  --> src/main.rs:16:41
   |
16 |         result = longest(str1.as_str(), another_str.as_str());
   |                                         ^^^^^^^^^^^ borrowed value does not live long enough
17 |     }
   |     - `another_str` dropped here while still borrowed
18 |     println!("The longest str is {}", result);
   |                                       ------ borrow later used here

error: aborting due to previous error

Can someone help me understand this behavior, please?

Thank you!

String literals are special, because they have an infinite lifetime ('static), so the borrow checker can allow them everywhere. Every other kind of reference is temporary.

A temporary borrow of a String has a lifetime tied to the scope where the String is. It can never escape past the scope it has been borrowed in, so the borrow checker won't let you use another_str (or anything that could possibly contain it) past the next }.

1 Like

The phrasing is a bit off here, and suggests that this would not work:

fn main() {
    let str1 = String::from("Holy test again!");
    let result;
    let another_str;  // declared outside
    {
        another_str = String::from("Inner str from scope.");
        result = longest(str1.as_str(), another_str.as_str());  // borrowed inside
    }
    println!("The longest str is {}", result);  // used outside
}

But of course this is perfectly valid.

How about "It can never escape the scope of the String variable it borrows from"?

1 Like

Hi!

Thank you for the explanation!

I am a Python programmer and these behaviors are really new to me, but I will get used to it. Actually I enjoying learn Rust, but I feel there is a long path to run and I hope someday I can help others fellows here in this same forum.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.