tarski
tarski

Reputation: 330

A simple test case to check my understanding of rust lifetimes

Just got done reading the rust book chapter on lifetimes.

Everything made mostly made sense, in particular one of the main examples being that the following will not compile

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

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);
}

This is because "We’ve told Rust that the lifetime of the reference returned by the longest function is the same as the smaller of the lifetimes of the references passed in. Therefore, the borrow checker disallows the code in Listing 10-24 as possibly having an invalid reference." And in another part of the chapter "the lifetime of the reference returned by the longest function is the same as the smaller of the lifetimes of the references passed in. "

So naturally I try to come up with my own simplified example as follows

fn foo<'a>(x: &'a str) -> &'a str {                                                
    x                                                                              
}                                                                                  
                                                                                   
fn main() {                                                                        
                                                                                   
    let y;                                                                         
    {                                                                              
        let x = "hello";                                                           
        y = foo(x);                                                                
    }                                                                              
    println!("y: {}", y);                                                          
}  

And to my surprise this compiles and runs just fine. How? Shouldn't the reference y have its lifetime end when x goes out of scope?

Upvotes: 2

Views: 244

Answers (1)

effect
effect

Reputation: 1455

The reason this works is that "hello" has a static lifetime, x is simply a reference to that static string. It's ok for x itself to go out of scope, the resource it references has a static lifetime and therefore lives long enough for y.

If we instead make x point to a std::String, we get the error you would expect:

fn foo<'a>(x: &'a str) -> &'a str {                                                
    x                                                                              
}                                                                                  
                                                                                   
fn main() {                                                                        
                                                                                   
    let y;                                                                         
    {                                                                              
        let x = String::from("hello");                                                           
        y = foo(&x);                                                                
    }                                                                              
    println!("y: {}", y);                                                          
}  
error[E0597]: `x` does not live long enough
  --> src/main.rs:10:17
   |
10 |         y = foo(&x);                                                                
   |                 ^^ borrowed value does not live long enough
11 |     }                                                                              
   |     - `x` dropped here while still borrowed
12 |     println!("y: {}", y);                                                          
   |                       - borrow later used here

Upvotes: 3

Related Questions