本页目录

Rust I · 所有权与借用检查

对标The Rust Programming Language(官方书)/ Stanford CS110L | 前置:csapp-04(内存之痛)、pl-02(三条内存管理路线) Rust 是过去十年最重要的系统语言创新——它做到了看似矛盾的事:没有垃圾回收、也不手动管理内存,却在编译期消灭了内存 bug 和数据竞争。秘密是所有权(ownership)——把"谁拥有内存、何时释放"编码进类型系统。这一页把 csapp-04 的所有内存灾难和 pl 线的类型纪律汇到一起:你会看到 C 的痛如何被编译器一条条提前拦下。本站系统线与语言线在此交汇。

1. 问题回顾:内存管理的三难

pl-02 讲过三条路线,各有硬伤:

Rust 的赌注:把内存安全从"运行时检查/程序员自律"提前到"编译期类型检查"——编译通过就保证无这类 bug。这是 pl 线"把运行时错误编码进类型"哲学的巅峰应用

2. 所有权三定律

Rust 的核心,就三条规则:

  1. 每个值有唯一的所有者(owner)(一个变量)。
  2. 同一时刻只有一个所有者
  3. 所有者离开作用域时,值被自动释放(drop)

规则 3 = 自动的、确定性的内存释放——不用手动 free(无泄漏),也不用 GC(无停顿、无不确定回收时机)。"作用域结束即释放"是 C++ 的 RAII 思想被 Rust 变成语言强制规则(🔗 与 pl-02 GC 对比:GC 是运行时追踪可达性,所有权是编译期跟踪作用域)。

移动语义(move)let b = a;a 是拥有堆内存的类型(如 String),所有权从 a 移动到 b,a 之后不可用(编译器拒绝再用 a)。这防止了"两个变量都以为自己拥有、各自释放 → 二次释放"(csapp-04 的灾难之一)——编译期就杜绝。要真复制用 .clone()(显式、你知道有成本)。

3. 借用与借用检查器:核心魔法

老是移动所有权太麻烦(传给函数就不能再用了)。借用(borrow)——临时引用而不夺走所有权,分两种,规则是 Rust 的灵魂:

借用铁律:任一时刻,要么多个不可变借用(&T,只读),要么恰好一个可变借用(&mut T,可写)——二者不可同时

这条"共享不可变、可变不共享(shared XOR mutable)"的规则,一举消灭多类 bug:

借用检查器(borrow checker)就是执行这些规则的编译器组件。它拒绝你的代码时,几乎总是它对——它发现了一个你没注意的别名/生命周期问题。学 Rust 的过程就是学会"把借用检查器的拒绝读成设计信号"([实验 L11] 就是练这个)。

4. 生命周期:引用有效性的显式化

生命周期标注('a)告诉编译器"这些引用要活多久、谁不能比谁先死"。多数情况编译器自动推断(生命周期省略),复杂时要手写 fn longest<'a>(x: &'a str, y: &'a str) -> &'a str——"返回的引用活得和输入一样久"。生命周期不是运行时的东西,是编译期的"引用有效性证明"(🔗 pl-01 类型即证明:生命周期是"这个引用不会悬垂"的证明)。初学最烧脑,但理解后你会发现它只是把"这块内存什么时候还有效"这个 C 程序员一直在脑子里心算的东西,变成编译器帮你验证

5. 所有权带来的其他好处

读法Rust 的学习曲线陡,是因为它把"内存和并发的正确性"这个 C 程序员用多年经验和纪律维持的东西,前置成了必须一开始就交代清楚的编译期契约。痛在前面、收益在后面(编译过了就很少运行时内存/并发 bug)。对你这个"想补系统肌肉记忆"的人,Rust 是最好的老师——它逼你把 csapp-04 那些隐性的内存规则显式想清楚

6. 练习与要点

例 1(移动 vs 借用) 写一个函数接收 String——用 String(移动,之后原变量不可用)vs &String(借用,之后还能用),体会所有权转移。理解"传值即交出所有权"

例 2(借用检查器拒绝你) 故意写"持有不可变借用时又要可变借用"的代码,读编译器错误、理解它拦下了什么潜在 bug——[L11] 的核心练习:把拒绝读成保护

例 3(生命周期必要性) 写一个返回两个字符串引用中较长者的函数,看编译器要求生命周期标注——理解"编译器需要知道返回的引用来自哪个输入、能活多久"。生命周期从抽象变具体\(\blacksquare\)

▶ 实验 L11(Rust 所有权谜题集)labs/L11-rust-ownership/ —— 一组"借用检查器拒绝"的代码,逐个理解为什么被拒 + 如何修。跑在 Mac(Rust)。目标:把编译错误读成设计信号,而非障碍。


下一页:Rust II——并发、trait 与 unsafe 边界:所有权如何兑现"无畏并发",trait 的抽象能力,以及什么时候必须跳出安全网。