How does this code compile successfully?

I am currently learning rust and I am now at lifetimes. I am a confused as to how the following code works;

fn main() {
    let word;
    {
        let text = "hello";
        word = word_func(text);
    }
    println!("{word}");
}

fn word_func<'a, 'b>(s: &'b str) -> &'b str {
    s
}

My thought process is this;
'a = everything from let word to println!("{word}");.
'b = the scope from line 3 - 6

So if the output and input of the function is 'b, which returned reference to text variable, then why is it that when I print word, it doesn't cause any error, considering the print statement is outside the scope of the returned reference?

Similar to how this will return an error;

fn main() {
    let word;
    {
        let text = "hello";
        word = &text;
    }
    println!("{word}");
}
  1. "hello" is of type &'static str (as are all string literals).
  2. Therefore, text is of type &'static str.
  3. Therefore, word is of type &'static str (because word_func has the same output as input).
  4. Therefore, there are no short lifetimes involved (except in the body of word_func, which has to be able to work with short lifetimes, but isn't here).
  5. Therefore, there is no error.

You would get the error you expect if you instead use a shorter-lived &str:

    {
        let text = String::from("hello");
        word = word_func(&text);
    }

Now, word is indeed a borrow of the str owned by the String owned by text, and so the code does not compile:

error[E0597]: `text` does not live long enough
 --> src/main.rs:5:26
  |
4 |         let text = String::from("hello");
  |             ---- binding `text` declared here
5 |         word = word_func(&text);
  |                          ^^^^^ borrowed value does not live long enough
6 |     }
  |     - `text` dropped here while still borrowed
7 |     println!("{word}");
  |               ------ borrow later used here
9 Likes

Hi,

I think word_func() is redundant, and the below func_b() is what you want.

You may ignore variable type, your code with an error returned version has been commented as func_a().

Please compare func_a() and func_b() carefully, and a memory layout picture can help you, too.

fn func_a() {
    let word;
    {
        let text: &str = "hello";
        word = &text; // word is deduced to '&&str' type, and point to text variable
        assert_eq!(core::mem::size_of_val(&word), 8); // word is thin pointer, only usize: 8
    } // text dies here, so word is invalid
    // println!("{word}");
}

fn func_b() {
    let word;
    {
        let text: &str = "hello";
        word = text; // word is deduced to '&str' type, and point to "hello"
        assert_eq!(core::mem::size_of_val(&word), 16); // word is fat pointer (same as text), two usizes: 16
    }
    println!("{word}");
}

2 Likes

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.