In this lesson, you will learn how the Rust compiler prevents "dangling pointers" by enforcing strict lifetime rules on references.
The Problem: Dangling Pointers
In many programming languages, you can create a reference to a piece of data, but that data might be destroyed while your reference is still pointing to it. This leads to a "dangling pointer"—a memory address that no longer contains valid data. If you try to read from it, your program will likely crash or behave unpredictably.
Rust stops this entirely at compile time using the Borrow Checker.
The Rule of Scope
The Borrow Checker enforces a simple, golden rule: A reference can never outlive the data it points to.
When you create a reference (a borrow), the compiler calculates the "lifetime" of that reference. It ensures that the owner of the data remains in scope for the entire time that any references to it exist.
Consider this invalid code:
fn main() {
let r;
{
let x = 5;
r = &x; // We borrow x here
} // x is dropped here (it goes out of scope)
println!("{}", r); // Error: `x` does not live long enough
}
In the example above, x is dropped when the inner scope { } ends. However, the reference r tries to access that memory after the scope has closed. The Rust compiler sees that r is trying to point to memory that has already been deallocated, so it refuses to compile the code.
Why This Matters
By forcing you to keep your references within the bounds of the owner's lifetime, Rust guarantees that you will never have a dangling pointer. You don't have to manually track when data is safe to use; the compiler tracks the "scope" of every variable and ensures that references are always pointing to valid, "alive" memory. If the data is gone, the compiler ensures the reference is gone, too.
Key Takeaway: The Borrow Checker prevents memory bugs by ensuring that no reference can ever point to data that has already been dropped or deallocated.