Question about lifetime and borrow

I am confused about lifetime and borrow in the official guide (chapter 10, lifetime and borrow),here are some codes which can show my confuses:
Example 1:

fn compare<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
    if x > y {
        x
    } else {
        y
    }
}
fn main() {
    let origin = 3;
    let x = &origin;
    let result;
    {
        let temp = 4;
        let y = &temp;
        result = compare(x, y);  // the compiler  points that `temp` does not live long enough borrowed value does not live long enoughrustcE0597 
    }
    print!("{:?}", result);
}

The code above i can understand the behavior of compiler.

But the below code let me confused:
Example 2:

fn compare<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
    if x > y {
        x
    } else {
        y
    }
}
fn main() {
    let x = &3;
    let result;
    {
        let y = &4;
        result = compare(x, y);   // the compiler passes it
    }
    print!("{:?}", result);  // the console print : 4
}

In my opinion,the y should be released in inner block like the first example, but obviously it was not released. :joy:
So,my question is : dose behavior of let y = &4 have any diffrences with let temp = 4;let y = &temp; ? (maybe in memory allocation or something else ?) :cold_sweat:

Here is my enviornment:
image

The thing is that y being a reference is not "released", where by released I mean dropped.
The lifetime of the variable y is the inner block - you cannot use it outside it. However, y holds a reference - so in order for result to be contain a valid reference, the thing that y has a reference to must "live" long-enough.
Now, look at y - it contains &4, which is a reference to a constant (something that can potentially live "forever"). Therefore, the compiler can treat the &4 as an &'static 4 - which means that the reference to 4 is valid for the entire lifetime of the program.
That's why the compiler passes it.
On the other hand, if you have let temp = 4; let y = &temp;, the lifetime of the reference that y holds is limited to the lifetime of the variable temp. Since, temp is valid only for the inner scope, so is the reference that is contained in y. On, the other hand, the lifetime of the reference stored in x definitely lasts at least as long as the one in y. But the problem is in result - the reference it contains must live until the print statement. Given the lifetimes you have used for compare, the compiler must choose something that definitely fits - therefore it mandates that 'a corresponds to a lifetime that lives at least until the print statement. And there lies the problem, the reference stored in y doesn't live until the print statement.
Formally, this is known as variance. If you want to know more about this, you can watch this video by Jon Gjengset - it is really good.

1 Like

See also 1414-rvalue_static_promotion - The Rust RFC Book.

1 Like

Whenever you're investigating lifetime weirdness, I suggest avoiding trivial Copy types like i32 literals.

If you do the same thing with a String, you'll get the temporary error again:

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:12:18
   |
12 |         let y = &String::from("world");
   |                  ^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
13 |         result = compare(x, y);   // the compiler passes it
14 |     }
   |     - temporary value is freed at the end of this statement
15 |     print!("{:?}", result);  // the console print : 4
   |                    ------ borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=dafcab763fc80ab350babcb9d6602f5b

1 Like

Thank you for your help and video, guys. I know the reason from your replay now, i will watch this video lately,thank you. :upside_down_face:

Thank you, guys.After i get more knowledge with rust, i may impressively understand the meaning from your suggestion .Now i will try remember your suggestion temporally.

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.