m03-mutability

Original🇺🇸 English
Translated

CRITICAL: Use for mutability issues. Triggers: E0596, E0499, E0502, cannot borrow as mutable, already borrowed as immutable, mut, &mut, interior mutability, Cell, RefCell, Mutex, RwLock, 可变性, 内部可变性, 借用冲突

2installs
Added on

NPX Install

npx skill4agent add zhanghandong/rust-skills m03-mutability

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

ErrorDon't Just SayAsk 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:
  1. Is mutation necessary?
    • Maybe transform → return new value
    • Maybe builder → construct immutably
  2. Who controls mutation?
    • External caller →
      &mut T
    • Internal logic → interior mutability
    • Concurrent access → synchronized mutability
  3. 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 ErrorTrace ToQuestion
Repeated borrow conflictsm09-domainShould data be restructured?
RefCell in asyncm07-concurrencyIs Send/Sync needed?
Mutex deadlocksm07-concurrencyIs the lock design right?

Trace Down ↓

From design to implementation:
"Need mutable access from &self"
    ↓ T: Copy → Cell<T>
    ↓ T: !Copy → RefCell<T>

"Need thread-safe mutation"
    ↓ Simple counters → AtomicXxx
    ↓ Complex data → Mutex<T> or RwLock<T>

"Need shared mutable state"
    ↓ Single-thread: Rc<RefCell<T>>
    ↓ Multi-thread: Arc<Mutex<T>>

Borrow Rules

At any time, you can have EITHER:
├─ Multiple &T (immutable borrows)
└─ OR one &mut T (mutable borrow)

Never both simultaneously.

Quick Reference

PatternThread-SafeRuntime CostUse When
&mut T
N/AZeroExclusive mutable access
Cell<T>
NoZeroCopy types, no refs needed
RefCell<T>
NoRuntime checkNon-Copy, need runtime borrow
Mutex<T>
YesLock contentionThread-safe mutation
RwLock<T>
YesLock contentionMany readers, few writers
Atomic*
YesMinimalSimple types (bool, usize)

Error Code Reference

ErrorCauseQuick Fix
E0596Borrowing immutable as mutableAdd
mut
or redesign
E0499Multiple mutable borrowsRestructure code flow
E0502&mut while & existsSeparate borrow scopes

Interior Mutability Decision

ScenarioChoose
T: Copy, single-thread
Cell<T>
T: !Copy, single-thread
RefCell<T>
T: Copy, multi-thread
AtomicXxx
T: !Copy, multi-thread
Mutex<T>
or
RwLock<T>
Read-heavy, multi-thread
RwLock<T>
Simple flags/counters
AtomicBool
,
AtomicUsize

Anti-Patterns

Anti-PatternWhy BadBetter
RefCell everywhereRuntime panicsClear ownership design
Mutex for single-threadUnnecessary overheadRefCell
Ignore RefCell panicHard to debugHandle or restructure
Lock inside hot loopPerformance killerBatch operations

Related Skills

WhenSee
Smart pointer choicem02-resource
Thread safetym07-concurrency
Data structure designm09-domain
Anti-patternsm15-anti-pattern