第3章 所有权

所有权与生命周期的深层规则

译文 · 基于 The Rustonomicon

所有权

原文链接: https://doc.rust-lang.org/nomicon/ownership.html

  所有权(ownership)是 Rust 的突破性特性。它使 Rust 完全内存安全且高效,又避免垃圾回收。在深入所有权系统前,我们先看这一设计的动机。

  我们假定你接受垃圾回收(GC)并非总是最优解,在某些上下文手动管理内存是可取的。若不接受,要不要考虑别的语言?

  无论你对 GC 看法如何,它显然对代码安全是巨大裨益。你不必再担心东西消失太早(尽管你是否仍想指向那东西是另一回事……)。这是 C 与 C++ 程序须应对的普遍问题。考虑这个我们都曾在非 GC 语言里犯过的简单错误:

fn as_str(data: &u32) -> &str {
    // 计算字符串
    let s = format!("{}", data);

    // 糟了!我们返回了只在本函数内
    // 存在之物的引用!
    // 悬垂指针!释放后使用!
    // (这在 Rust 中不能编译)
    &s
}

  这正是 Rust 所有权系统要解决的。Rust 知道 &s 存活的作用域,因而可阻止其逃逸。但这是 C 编译器也许能抓到的简单情况。代码变大、指针经各函数传递时更复杂。最终 C 编译器会力有不逮,无法做足够逃逸分析证明代码不健全,因而被迫在假定正确的前提下接受程序。

  这在 Rust 中不会发生。须由程序员向编译器证明一切健全。

  当然,Rust 围绕所有权的故事远不只是验证引用不逃逸被引用对象的作用域。因为确保指针始终有效远比这复杂。例如在本代码中,

let mut data = vec![1, 2, 3];
// 取得内部引用
let x = &data[0];

// 糟了!`push` 导致 `data` 后备存储重新分配。
// 悬垂指针!释放后使用!
// (这在 Rust 中不能编译)
data.push(4);

println!("{}", x);

  朴素的作用域分析不足以防止此 bug,因为 data 确实活得够久。但我们在持有其引用时改变了它。因此 Rust 要求任何引用冻结被引用对象及其 owner。


3.1 引用

引用的语义与规则

3.2 别名

别名为何重要

3.3 生命周期

生命周期的含义与作用范围

3.4 生命周期的局限

生命周期检查的边界与不当缩减借用

3.5 生命周期省略

生命周期省略规则

3.6 无界生命周期

无界生命周期及其危险性

3.7 高阶 trait 约束(HRTB)

高阶 trait 约束 for<‘a>

3.8 子类型与型变

子类型关系与型变

3.9 Drop 检查

dropck 与逃逸舱口

3.10 PhantomData

PhantomData 与 drop 检查

3.11 拆分借用

如何安全地拆分借用

最后修改 August 11, 2026: 更新 (70a5af133)