m03-mutability by zhanghandong/rust-skills
npx skills add https://github.com/zhanghandong/rust-skills --skill m03-mutability第一层:语言机制
为什么这些数据需要改变,以及谁可以改变它?
在添加内部可变性之前,请理解:
| 错误 | 不要只是说 | 而是问 |
|---|---|---|
| E0596 | "添加 mut" | 这真的需要是可变的吗? |
| E0499 | "分割借用" | 数据结构是否正确? |
| E0502 | "分离作用域" | 为什么我们需要两个借用? |
| RefCell panic | "使用 try_borrow" | 运行时检查是否合适? |
在添加可变性之前:
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
谁控制可变性?
&mut T线程上下文是什么?
当可变性冲突持续存在时:
E0499/E0502 (借用冲突)
↑ 问:数据结构设计是否正确?
↑ 检查:m09-domain (数据应该被拆分吗?)
↑ 检查:m07-concurrency (是否涉及异步?)
| 持续错误 | 追溯到 | 问题 |
|---|---|---|
| 重复的借用冲突 | m09-domain | 数据应该重构吗? |
| async 中的 RefCell | m07-concurrency | 需要 Send/Sync 吗? |
| Mutex 死锁 | m07-concurrency | 锁的设计正确吗? |
从设计到实现:
"需要从 &self 进行可变访问"
↓ T: Copy → Cell<T>
↓ T: !Copy → RefCell<T>
"需要线程安全的可变性"
↓ 简单计数器 → AtomicXxx
↓ 复杂数据 → Mutex<T> 或 RwLock<T>
"需要共享可变状态"
↓ 单线程:Rc<RefCell<T>>
↓ 多线程:Arc<Mutex<T>>
在任何时候,你可以有 EITHER:
├─ 多个 &T (不可变借用)
└─ 或者一个 &mut T (可变借用)
永远不能同时拥有两者。
| 模式 | 线程安全 | 运行时成本 | 使用场景 |
|---|---|---|---|
&mut T | 不适用 | 零 | 独占可变访问 |
Cell<T> | 否 | 零 | Copy 类型,不需要引用 |
RefCell<T> | 否 | 运行时检查 | 非 Copy,需要运行时借用 |
Mutex<T> | 是 | 锁竞争 | 线程安全可变性 |
RwLock<T> | 是 | 锁竞争 | 多读少写 |
Atomic* | 是 | 最小 | 简单类型 (bool, usize) |
| 错误 | 原因 | 快速修复 |
|---|---|---|
| E0596 | 将不可变借用为可变 | 添加 mut 或重新设计 |
| E0499 | 多个可变借用 | 重构代码流程 |
| E0502 | 存在 & 时使用 &mut | 分离借用作用域 |
| 场景 | 选择 |
|---|---|
| T: Copy, 单线程 | Cell<T> |
| T: !Copy, 单线程 | RefCell<T> |
| T: Copy, 多线程 | AtomicXxx |
| T: !Copy, 多线程 | Mutex<T> 或 RwLock<T> |
| 读多写少,多线程 | RwLock<T> |
| 简单标志/计数器 | AtomicBool, AtomicUsize |
| 反模式 | 为什么不好 | 更好的选择 |
|---|---|---|
| 到处使用 RefCell | 运行时恐慌 | 清晰的所有权设计 |
| 单线程使用 Mutex | 不必要的开销 | RefCell |
| 忽略 RefCell panic | 难以调试 | 处理或重构 |
| 在热循环内加锁 | 性能杀手 | 批量操作 |
| 何时 | 参见 |
|---|---|
| 智能指针选择 | m02-resource |
| 线程安全 | m07-concurrency |
| 数据结构设计 | m09-domain |
| 反模式 | m15-anti-pattern |
每周安装量
613
代码仓库
GitHub 星标数
912
首次出现
2026年1月20日
安全审计
安装于
opencode561
codex545
gemini-cli534
github-copilot525
amp478
kimi-cli473
Layer 1: Language Mechanics
Why does this data need to change, and who can change it?
Before adding interior mutability, understand:
| 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? |
Before adding mutability:
Is mutation necessary?
Who controls mutation?
&mut TWhat's the thread context?
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? |
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>>
At any time, you can have EITHER:
├─ Multiple &T (immutable borrows)
└─ OR one &mut T (mutable borrow)
Never both simultaneously.
| Pattern | Thread-Safe | Runtime Cost | Use When |
|---|---|---|---|
&mut T | N/A | Zero | Exclusive mutable access |
Cell<T> | No | Zero | Copy types, no refs needed |
RefCell<T> | No | Runtime check | Non-Copy, need runtime borrow |
Mutex<T> | Yes | Lock contention | Thread-safe mutation |
| Error | Cause | Quick Fix |
|---|---|---|
| E0596 | Borrowing immutable as mutable | Add mut or redesign |
| E0499 | Multiple mutable borrows | Restructure code flow |
| E0502 | &mut while & exists | Separate borrow scopes |
| Scenario | Choose |
|---|---|
| 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, |
| Anti-Pattern | Why Bad | Better |
|---|---|---|
| RefCell everywhere | Runtime panics | Clear ownership design |
| Mutex for single-thread | Unnecessary overhead | RefCell |
| Ignore RefCell panic | Hard to debug | Handle or restructure |
| Lock inside hot loop | Performance killer | Batch operations |
| When | See |
|---|---|
| Smart pointer choice | m02-resource |
| Thread safety | m07-concurrency |
| Data structure design | m09-domain |
| Anti-patterns | m15-anti-pattern |
Weekly Installs
613
Repository
GitHub Stars
912
First Seen
Jan 20, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode561
codex545
gemini-cli534
github-copilot525
amp478
kimi-cli473
React 组合模式指南:Vercel 组件架构最佳实践,提升代码可维护性
103,800 周安装
RwLock<T>| Yes |
| Lock contention |
| Many readers, few writers |
Atomic* | Yes | Minimal | Simple types (bool, usize) |
AtomicUsize