本章要回答的三个问题:值为什么只能有一个所有者?借用与引用的权限边界在哪里?生命周期标注到底在声明什么?
第 1 章的三份内存事故卷宗在这里正式开庭。所有权系统是 Rust 的根本法:它决定每块堆内存何时释放(所有权)、谁能访问(借用)、访问权何时失效(生命周期)。绝大多数"Rust 太难"的抱怨,本质是没把这三条法条当成一个体系来理解。本章按庭审顺序走:先立产权,再发旁听证,最后核验证词有效期。
| 节 | 回答哪个问题 | 关键产出 |
|---|---|---|
| 3.1 所有权三铁律 | 内存归谁、何时释放 | 移动与克隆的判断流程 |
| 3.2 借用与引用 | 不转移产权如何访问 | 借用铁律与三类高频案件 |
| 3.3 生命周期 | 引用凭什么不悬垂 | 标注语法与省略规则 |
所有权判例贯穿后续所有章节:第 5 章Trait 对象的生存期、第 8 章跨线程的产权移交,都是本章法条在新辖区的适用。
三堂庭审的结论可以压缩成一张口袋卡,遇到报错先对号,再回对应节复庭。
| 报错 | 案情一句话 | 对应节 |
|---|---|---|
| E0382 | 值已移动却还在用 | 3.1 移动语义 |
| E0388 | 部分移动后整体再用 | 3.1 部分移动 |
| E0502 | 读写借用区间重叠 | 3.2 借用铁律 |
| E0499 | 可变借用出现两次 | 3.2 借用铁律 |
| E0506/E0507 | 想把值移出借用 | 3.2 借用铁律 |
| E0597 | 引用活得比数据久 | 3.3 生命周期 |
| E0106 | 缺生命周期标注 | 3.3 生命周期 |
本章不宜一次性读完。3.1 与 3.2 可以连读,因为移动与借用互为镜像——一个是产权移交,一个是产权出借;3.3 建议隔一天再开,生命周期引入了新的符号系统,混在一起容易把 'a 误解为某种类型参数。自测方案:找三段自己以前写的代码(或任何开源片段),逐行标注每个 String 的产权归属与每个引用的存活区间,标注不出来的一行,就是需要回庭的那一节。
本章立的三条法在第 5 章遇到 trait 对象时会出现新条款——Box<dyn Trait> 里藏着一个默认 'static 约束;在第 8 章跨线程场景下升级为 Send 与 Sync 两大检查。到那时回看本章会发现,所有权、借用、生命周期其实是同一条原则的三次适用:一切访问权限都必须能被静态证明。把这句话记住,Rust 的难点就从"规则多"变成"规则少而执法严"。
产权唯一:值只有一个所有者,赋值即移交。访问凭票:一写或多读,票的有效期是控制流区间而非文本顺序。证词有期:引用不得活得过数据,标注只约束不续命。三句话写进便签,遇到报错先背一遍再读报错,多数时候方向自动浮现。
一问:let v = vec![1,2,3]; let w = v; 之后 v 还能用吗,为什么?答:不能,Vec 持堆缓冲属 Move,E0382 候审。二问:函数签名 fn f(s: &mut String) 与 fn f(s: String) 对调用方的区别?答:前者租借可写权限、用后收回,后者索取产权、交出不返。三问:为什么 &'static str 可以从任何函数返回,而局部 String 的引用不行?答:字面量存于二进制只读区、活满全程,局部值随栈帧销毁。三题全对再进第 4 章,数据结构一章不过是本章法条在更大卷宗上的适用。