Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can borrowed string literal outlive its owner by faking a lifetime?

I understand that a borrow cannot outlive the existence of the thing it points to, to eradicate the dangling pointers.

A borrow or an alias can outlive the owner by faking the lifetimes:

fn main() {
    let e;
    let first = "abcd";
    {
        let second = "defgh";
        e = longest(first, second);
    }
    println!("{}", e);
}

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

Result:

defgh

In the above example, the variable e has a longer lifetime than the second variable and clearly the first & second variables lifetimes are different.

When e is initialized with longest(first, second) it gets the second variable whose lifetime to function call is faked as it is equal to first but it is confined to the block and it is assigned to e which will outlive the second. Why is this OK?

like image 938
Pawan Kumar Avatar asked Jan 09 '19 17:01

Pawan Kumar


1 Answers

This is due to the fact that both of these have the 'static lifetime.

Here's an example that doesn't work because the str here does not live for the life of the program like a &'static str does. The only change is the following line: let second = String::from("defgh"); and the next line where it is passed to the longest function.

fn main() {
    let e;
    let first = "abcd";
    {
        let second = String::from("defgh");
        e = longest(first, &second);
    }
    println!("{}", e);
}

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

Here's the error:

error[E0597]: `second` does not live long enough
 --> src/main.rs:6:28
  |
6 |         e = longest(first, &second);
  |                            ^^^^^^^ borrowed value does not live long enough
7 |     }
  |     - `second` dropped here while still borrowed
8 |     println!("{}", e);
  |                    - borrow later used here

More information can be found in Static - Rust By Example

like image 167
Marcus Avatar answered Oct 22 '22 05:10

Marcus