borrowing_rules.md (2811B)
1 # Borrowing Rules 2 3 Rust enforces two hard rules at compile time: 4 5 1. You can have any number of immutable references (&T) at the same time 6 7 2. You can have only one mutable reference (&mut T) at a time — and when a 8 mutable reference is active, no immutable references may exist either 9 10 ### String example: 11 12 #### Question: Why does rust only allow one muatble reference at a time? 13 14 A String in Rust is heap-allocated and stores a pointer, a length, and a 15 capacity internally. If you hold an immutable reference r1 to a String and then 16 mutate it via a second mutable reference r2 — say by pushing characters — the 17 String may reallocate its internal buffer to a new heap address. At that point, 18 r1 would be pointing to freed memory, which is a dangling pointer and causes 19 [undefined behavior](/memory_safety/segfault.md). Rust prevents this entirely at 20 compile time. 21 22 ```rust 23 let mut s = String::from("hello"); 24 25 let r1 = &s; // ✅ immutable borrow 26 let r2 = &s; // ✅ another immutable borrow — fine! 27 let r3 = &mut s; // ❌ compile error: can't borrow mutably while r1/r2 exist 28 ``` 29 30 ### Furthermore: 31 32 The single mutable reference rule actually solves several classes of bugs 33 simultaneously: 34 35 - Dangling pointers — mutation causes reallocation, invalidating old references 36 (your example) 37 38 - Data races — two threads mutating the same memory simultaneously leads to 39 unpredictable results 40 41 - [Iterator invalidation](iterator_invalidation.md) — modifying a collection 42 while iterating over it (a common bug in C++ and Java) 43 44 - Compiler optimisation safety — the compiler can safely optimise and even 45 vectorise (SIMD) code because it knows no two mutable aliases can overlap 46 47 ## Mutable Reference [Lifetime](/memory_safety/lifetime.md) Is Scoped 48 49 The borrow checker is smart enough to track when a reference's last use is, not 50 just its scope. This means a mutable reference can be created once the immutable 51 ones are no longer actively used: 52 53 ```rust 54 let mut s = String::from("hello"); 55 56 let r1 = &s; 57 let r2 = &s; 58 println!("{r1}, {r2}"); // r1 and r2 last used here — they're effectively dropped 59 60 let r3 = &mut s; // ✅ now safe, no active immutable refs 61 r3.push_str(", world"); 62 ``` 63 64 This feature is called 65 [Non-Lexical Lifetimes (NLL)](/memory_safety/non_lexical_lifetimes.md) and was 66 introduced to make Rust's borrow checker less restrictive while keeping it safe. 67 68 ## References: 69 70 [Why Does Rust Enforce the “One Mutable or Many Immutable References” Rule in Single-Threaded Programs?](https://users.rust-lang.org/t/why-does-rust-enforce-the-one-mutable-or-many-immutable-references-rule-in-single-threaded-programs/121017/2) 71 72 [The Problem With Single-threaded Shared Mutability](https://manishearth.github.io/blog/2015/05/17/the-problem-with-shared-mutability/)