3.1 引用
引用的语义与规则
2 分钟阅读
译文 · 基于 The Rustonomicon
所有权(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。
引用的语义与规则
别名为何重要
生命周期的含义与作用范围
生命周期检查的边界与不当缩减借用
生命周期省略规则
无界生命周期及其危险性
高阶 trait 约束 for<‘a>
子类型关系与型变
dropck 与逃逸舱口
PhantomData 与 drop 检查
如何安全地拆分借用