borrowing_rules.txt (2661B)
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 Rust prevents this entirely at compile time. 20 21 ```rust 22 let mut s = String::from("hello"); 23 24 let r1 = &s; // ✅ immutable borrow 25 let r2 = &s; // ✅ another immutable borrow — fine! 26 let r3 = &mut s; // ❌ compile error: can't borrow mutably while r1/r2 exist 27 ``` 28 29 ### Furthermore: 30 31 The single mutable reference rule actually solves several classes of bugs 32 simultaneously: 33 34 - Dangling pointers — mutation causes reallocation, invalidating old references 35 (your example) 36 37 - Data races — two threads mutating the same memory simultaneously leads to 38 unpredictable results 39 40 - Iterator invalidation — modifying a collection 41 while iterating over it (a common bug in C++ and Java) 42 43 - Compiler optimisation safety — the compiler can safely optimise and even 44 vectorise (SIMD) code because it knows no two mutable aliases can overlap 45 46 ## Mutable Reference Lifetime Is Scoped 47 48 The borrow checker is smart enough to track when a reference's last use is, not 49 just its scope. This means a mutable reference can be created once the immutable 50 ones are no longer actively used: 51 52 ```rust 53 let mut s = String::from("hello"); 54 55 let r1 = &s; 56 let r2 = &s; 57 println!("{r1}, {r2}"); // r1 and r2 last used here — they're effectively dropped 58 59 let r3 = &mut s; // ✅ now safe, no active immutable refs 60 r3.push_str(", world"); 61 ``` 62 63 This feature is called 64 Non-Lexical Lifetimes (NLL) and was 65 introduced to make Rust's borrow checker less restrictive while keeping it safe. 66 67 ## References: 68 69 [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) 70 71 [The Problem With Single-threaded Shared Mutability](https://manishearth.github.io/blog/2015/05/17/the-problem-with-shared-mutability/)