Non-lexical lifetimes
for 2018 edition
for 2015 edition
The borrow checker has been enhanced to accept more code, via a mechanismcalled "non-lexical lifetimes." Consider this example:
fn main() {
let mut x = 5;
let y = &x;
let z = &mut x;
}
In older Rust, this is a compile-time error:
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
--> src/main.rs:5:18
|
4 | let y = &x;
| - immutable borrow occurs here
5 | let z = &mut x;
| ^ mutable borrow occurs here
6 | }
| - immutable borrow ends here
This is because lifetimes follow "lexical scope"; that is, the borrow from y
isconsidered to be held until y
goes out of scope at the end of main
, even thoughwe never use y
again. This code is fine, but the borrow checker could not handle it.
Today, this code will compile just fine.
Better errors
What if we did use y
, like this?
fn main() {
let mut x = 5;
let y = &x;
let z = &mut x;
println!("y: {}", y);
}
Here's the error:
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
--> src/main.rs:5:18
|
4 | let y = &x;
| - immutable borrow occurs here
5 | let z = &mut x;
| ^ mutable borrow occurs here
...
8 | }
| - immutable borrow ends here
With non-lexical lifetimes, the error changes slightly:
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
--> src/main.rs:5:13
|
4 | let y = &x;
| -- immutable borrow occurs here
5 | let z = &mut x;
| ^^^^^^ mutable borrow occurs here
6 |
7 | println!("y: {}", y);
| - borrow later used here
Instead of pointing to where y
goes out of scope, it shows you wherethe conflicting borrow occurs. This makes these sorts of errors far easier to debug.