Mutability
Layer 1: Language Mechanics
Core Question
Why does this data need to change, and who can change it?
Before adding interior mutability, understand:
Is mutation essential or accidental complexity? Who should control mutation? Is the mutation pattern safe? Error → Design Question Error Don't Just Say Ask Instead E0596 "Add mut" Should this really be mutable? E0499 "Split borrows" Is the data structure right? E0502 "Separate scopes" Why do we need both borrows? RefCell panic "Use try_borrow" Is runtime check appropriate? Thinking Prompt
Before adding mutability:
Is mutation necessary?
Maybe transform → return new value Maybe builder → construct immutably
Who controls mutation?
External caller → &mut T Internal logic → interior mutability Concurrent access → synchronized mutability
What's the thread context?
Single-thread → Cell/RefCell Multi-thread → Mutex/RwLock/Atomic Trace Up ↑
When mutability conflicts persist:
E0499/E0502 (borrow conflicts) ↑ Ask: Is the data structure designed correctly? ↑ Check: m09-domain (should data be split?) ↑ Check: m07-concurrency (is async involved?)
Persistent Error Trace To Question Repeated borrow conflicts m09-domain Should data be restructured? RefCell in async m07-concurrency Is Send/Sync needed? Mutex deadlocks m07-concurrency Is the lock design right? Trace Down ↓
From design to implementation:
"Need mutable access from &self"
↓ T: Copy → Cell
"Need thread-safe mutation"
↓ Simple counters → AtomicXxx
↓ Complex data → Mutex
"Need shared mutable state"
↓ Single-thread: Rc
Borrow Rules At any time, you can have EITHER: ├─ Multiple &T (immutable borrows) └─ OR one &mut T (mutable borrow)
Never both simultaneously.
Quick Reference
Pattern Thread-Safe Runtime Cost Use When
&mut T N/A Zero Exclusive mutable access
Cell