What are the rules of borrowing?
Short answer: Two rules cover every borrow you will write. At any moment, a value has either any number of immutable borrows or exactly one mutable borrow — never both at the same time. And a borrow must always be valid: the value has to outlive the reference.
The two rules in one program
Section titled “The two rules in one program”From a fresh project — cargo new borrow-rules, then replace src/main.rs with the whole of this.
The project name doesn’t matter, because nothing in the output depends on it:
fn main() { let mut scores = vec![1, 2, 3];
let read1 = &scores; let read2 = &scores; println!("{read1:?} {read2:?}");
let write = &mut scores; write.push(4);
println!("{scores:?}");}[1, 2, 3] [1, 2, 3][1, 2, 3, 4]read1 and read2 are alive at the same moment — both are read by the first println! — and the
compiler allows it, because shared borrows don’t conflict with each other. write starts only after
the last use of the readers, and a single exclusive borrow is fine on its own. The push lands on the
original Vec, and the final println! prints what write left behind.
That is the whole of rule one. Many readers or one writer, and “many” and “one” are measured at a
moment in time, not per value forever: a &mut that begins after the readers have finished is as
legal as the readers were. How long a borrow counts as lasting is its own page later in this
chapter.
When rule one is broken
Section titled “When rule one is broken”Overlapping the two kinds is a compile error, and both variants have their real messages captured on
the & versus &mut page: E0502
when a mutable borrow starts while a shared one is still alive, and E0499 when two mutable borrows
overlap. Neither is a rule about &mut being rare — it’s a rule about overlap.
Rule two: a borrow must be valid
Section titled “Rule two: a borrow must be valid”The second rule is about time rather than exclusivity. A reference has to point at a value that is still alive wherever the reference is used:
fn main() { let r; { let s = String::from("hello"); r = &s; }
println!("{r}");}error[E0597]: `s` does not live long enough --> src/main.rs:5:13 |4 | let s = String::from("hello"); | - binding `s` declared here5 | r = &s; | ^^ borrowed value does not live long enough6 | } | - `s` dropped here while still borrowed7 |8 | println!("{r}"); | - borrow later used here
For more information about this error, try `rustc --explain E0597`.r is read by the println!, so the borrow has to be alive on that line — but s is dropped when
its block ends, one line earlier. The compiler refuses rather than leave a reference pointing at
freed memory. Move the owner out to meet the borrow and the same file compiles:
fn main() { let r; let s = String::from("hello"); r = &s;
println!("{r}");}helloThe other fix is to shorten the borrow: move the println! inside the block instead. Either way the
owner now covers every line that reads the reference, which is all rule two asks.
Related
Section titled “Related”- What is the difference between & and &mut? — the two kinds of borrow that rule one is about
- How to borrow a value — the
&that starts all of this - Borrowing — the rest of this chapter
- Next in this chapter: why does Rust allow many immutable borrows but only one mutable?