On-Ramp to Rust

the borrow checker

All the rules so far — one owner, move on assignment, many-shared-or-one-mutable — would be just polite suggestions if nothing checked them. The borrow checker is the part of the Rust compiler that does the checking. It is not a tool you run separately and it is not a runtime watchdog; it is a phase inside the compiler that, every time you build, reads your code and proves that every reference obeys the ownership and borrowing rules. If it can prove your program is safe, it compiles. If it finds even one way the rules could be broken, it stops with a borrow-check error and the program does not build.

What it actually does, in plain steps: for each value, it works out the span of code over which each borrow of that value is live (used). Then it checks the rules against those spans — that no borrow outlives the value it points to (so no reference can dangle), that no mutable borrow overlaps any other borrow of the same value, and that you never use a value after it has been moved away. A borrow-check error is the compiler telling you it could not prove one of these. The messages name the rule you tripped: cannot borrow as mutable because it is also borrowed as immutable, borrow of moved value, or borrowed value does not live long enough. Crucially these are compile-time errors — they happen on your machine, before anything ships, not as a crash in front of a user.

The honest part: the borrow checker is conservative. It only accepts code it can prove safe, so it will sometimes reject a program that would actually have been fine, because the proof was beyond what it could see. This is the famous fighting the borrow checker that newcomers experience. The right reaction is usually not to force the code through but to restructure it so the ownership story is clear — shorten a borrow, clone when you genuinely need two copies, or split a function. With practice the checker stops feeling like an adversary and starts feeling like a colleague who catches the exact memory mistakes that, in C, would have shipped silently and crashed weeks later.

fn main() { let r; { let x = 5; r = &x; // borrow x } // x dropped here println!("{r}"); // error[E0597]: `x` does not live long enough }

The checker rejects a reference that would outlive the value it points to -- caught at compile time.

A borrow-check error is not a bug in your program waiting to happen at runtime — it is the compiler refusing to let a known bug class exist at all. It is conservative, so a rejected program is sometimes safe; a rejection is never a false alarm about an accepted one.

Also called
borrowckthe checker借用檢查器