Search code examples
rustlifetimerust-rustlings

Variable re assigment causing lifetime issues


I am working through the rustlings exercises and I ran into something i don't fully understand about lifetime. I will simplify the code to just the confusing part.

This function compiles correctly:

fn string_uppercase(mut data: &String) {
    let newdata: &String = &data.to_uppercase();
}

this function doesnt

fn string_uppercase(mut data: &String) {
    data = &data.to_uppercase();
}

and shows the following error:

error[E0716]: temporary value dropped while borrowed
  --> exercises/06_move_semantics/move_semantics6.rs:25:13
   |
24 | fn string_uppercase(mut data: &String) {
   |                               - let's call the lifetime of this reference `'1`
25 |     data = &data.to_uppercase();
   |     --------^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
   |     |       |
   |     |       creates a temporary value which is freed while still in use
   |     assignment requires that borrow lasts for `'1`

error: aborting due to 1 previous error; 1 warning emitted

I have done some chatGPTing and SOflowing(E.g. this) and I understand the following:

  1. The data.to_uppercase() function call will create a new String
  2. This value is created in an expression and so it is called temporary as it will be dropped if it isn't saved in a variable.

This is clear, but what is the difference between trying to save it in data vs newdata. In both cases I am attempting to save this temporary value to avoid it getting dropped, but one works, and the other one doesnt.


Solution

  • The second example with explicit lifetimes:

    fn string_uppercase<'a>(mut data: &'a String) {
        // data has type &'a String
        data = &data.to_uppercase();
    }
    

    data.to_uppercase() creates a temporary variable which gets dropped at the end of the enclosing statement. This means that &data.to_uppercase() can't have type &'a String, it doesn't live long enough. The key fact is that the type of data is preserved when data is reassigned.

    In the first example newdata is a new variable and can thus have as short a lifetime as necessary. Therefore, it compiles.