Rustlers Atom 2.6: NLL (non-lexical lifetimes)

For a long time, Rust’s concept of a "lifetime" was strictly tied to lexical scope—the curly braces {}. If you created a reference inside a block, the compiler assumed that reference lived until the closing brace }, period.

This was safe, but annoying. It often rejected valid code because the compiler wasn't smart enough to see that you were done with a variable before the block ended.

Since the 2018 edition, Rust uses Non-Lexical Lifetimes (NLL). The borrow checker now looks at the control flow graph of your program. It knows that a reference’s life ends the last time it is used, not necessarily when it goes out of scope.

The "Interleaved" Borrows

Before NLL, the following code would fail to compile because mut_ref would "lock" the data variable until the end of the function. With NLL, Rust sees that mut_ref is used for the last time in the push line, so it releases the borrow immediately after.

fn main() {
    let mut data = vec![1, 2, 3];

    // 1. Create a mutable reference
    let mut_ref = &mut data; 
    mut_ref.push(4); 
    // --- `mut_ref` is no longer used after this point ---
    // Under NLL, the mutable borrow effectively ends HERE.

    // 2. Create an immutable reference
    // This is now allowed because the mutable borrow is "dead"
    let imm_ref = &data; 
    println!("{:?}", imm_ref); 
}

This feature reduces the need for "fighting the borrow checker." You don't need to artificially wrap code in extra {} blocks just to kill a borrow early. You can write code that flows naturally, and if the logic is sound, Rust will likely accept it.

Important Nuance: Drop vs. Liveness

NLL changes the liveness of references (when a borrow is active). It does not change when a value is dropped.

  • Borrows end at the last usage.
  • Owned values are dropped at the closing brace }.
struct LoudDrop;
impl Drop for LoudDrop {
    fn drop(&mut self) { println!("Dropped!"); }
}

fn main() {
    let x = LoudDrop;
    let y = &x; 

    println!("Used y"); 
    // y's borrow ends here (NLL)

    println!("End of main");
} // x is dropped here (Lexical Scope)

You'll only receive email when they publish something new.

More from GSLF
All posts