name: m03-mutability description: “关键:用于可变性问题。触发条件:E0596, E0499, E0502, cannot borrow as mutable, already borrowed as immutable, mut, &mut, interior mutability, Cell, RefCell, Mutex, RwLock, 可变性, 内部可变性, 借用冲突” user-invocable: false
可变性
第一层:语言机制
核心问题
为什么这些数据需要改变,以及谁可以改变它?
在引入内部可变性之前,请理解:
- 可变性是必需的还是偶然的复杂性?
- 谁应该控制可变性?
- 可变模式是否安全?
错误 → 设计问题
| 错误代码 | 不要只是说 | 而是应该问 |
|---|---|---|
| E0596 | “添加 mut” | 这真的需要可变吗? |
| E0499 | “拆分借用” | 数据结构设计正确吗? |
| E0502 | “分离作用域” | 为什么我们需要两种借用? |
| RefCell 恐慌 | “使用 try_borrow” | 运行时检查是否合适? |
思考提示
在添加可变性之前:
-
可变是必要的吗?
- 也许可以转换 → 返回新值
- 也许可以使用构建器 → 以不可变方式构造
-
谁控制可变性?
- 外部调用者 →
&mut T - 内部逻辑 → 内部可变性
- 并发访问 → 同步可变性
- 外部调用者 →
-
线程上下文是什么?
- 单线程 → Cell/RefCell
- 多线程 → Mutex/RwLock/Atomic
向上追溯 ↑
当可变性冲突持续存在时:
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>>
借用规则
在任何时刻,你只能拥有以下之一:
├─ 多个 &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 恐慌 | 难以调试 | 处理或重构 |
| 在热循环中加锁 | 性能杀手 | 批量操作 |
相关技能
| 何时 | 参见 |
|---|---|
| 智能指针选择 | m02-resource |
| 线程安全 | m07-concurrency |
| 数据结构设计 | m09-domain |
| 反模式 | m15-anti-pattern |