I don't understand why I am getting the following compiler error from this code:
struct Superhero<'a> { name: &'a String, power: &'a i32 } // 1
// 2
fn main() { // 3
let n = "Bruce Wayne".to_string(); // 4
let r; // 5
{ // 6
let p = 98; // 7
{ // 8
let hero = Superhero{ name: &n, power: &p }; // 9
r = hero.name; // 10
} // 11
println!("{}", r); // 12
} // 13
} // 14
Compiler Error: rustc 1.27.1 (5f2b325f6 2018-07-07)
error[E0597]: `p` does not live long enough
--> src/main.rs:9:53
|
9 | let hero = Superhero{ name: &n, power: &p };
| ^ borrowed value does not live long enough
...
13 | }
| - `p` dropped here while still borrowed
14 | }
| - borrowed value needs to live until here
Here is what I thought this code would do, line by line. There is something wrong with one or more of these lines, because this code does not compile.
4: Initialize name: String to "Bruce Wayne".to_string();
5: Declare r to be initialized in a different scope
6: Begin a new scope (A)
7: Initialize p to 98
8: Begin a new scope (B)
9: Initialize hero: Superhero to a new struct
hero.name refers to the variable{n},
hero.power refers to the variable{p}
10: Copy a reference to the variable{n},
since reference types are copy, both hero.name and r are distinct references to the variable{n}.
11: End scope (B): hero and the two references it owns {hero.name, hero.power} are dropped.
12: Print the value of the variable{r}: Should print "Bruce Wayne"
13: End scope (A): the variable{p} is dropped.
14: End scope for main. The variables {n, r} are dropped.
Why does the compiler error say that something is still borrowing p
on line 13? Shouldn't hero
(and subsequently hero.power
) have been dropped on line 11? There should be nothing referring to p
at this point.
Curiously, changing the order in which the values (p
and r
) are initialized fixes the issue, and I have no idea why.
Ways to fix:
- Move line 7
let p = 90;
between line 4 and line 5 - Move line 5
let r;
between line 7 and line 8
In both of these cases, simply declaring r
AFTER p
ensures that nothing is still "borrowing" p
when it is dropped. This makes no sense to me at all, because I feel like r
has nothing at all to do with p
, or with anything that may be borrowing p
.
This code runs with non-lexical lifetimes enabled.
What property of lexical lifetimes causes this to not compile, and what about non-lexical lifetimes fixes this issue?