notes

Log | Files | Refs

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/)