Explain the borrow checker with an example.
The borrow checker enforces the borrowing rules at compile time: you may have either one mutable reference or any number of immutable references, and references must always be valid.
fn main() {
let mut v = vec![1, 2, 3];
let first = &v[0]; // immutable borrow
v.push(4); // error: cannot borrow as mutable
println!("{first}"); // first is still used here
}
The immutable borrow is still alive at the push, so Rust rejects the program. Fixes include copying the value with first.copied(), letting the borrow end before mutating, or reordering the statements.
Another classic case is returning a reference to a local variable: the borrow checker sees that it would dangle and refuses to compile. This eliminates use-after-free, iterator invalidation and data races without runtime cost. When the checker feels too strict, reach for indices, cloning or a restructure so borrows do not overlap rather than sprinkling unsafe.