本页目录
引用与借用
Rust 借用检查器只认一条规则:同一时刻,要么一个可变引用,要么多个不可变引用,两者不共存(aliasing XOR mutation)。NLL 把检查粒度从词法作用域细化到实际使用区间,reborrow 让嵌套借用不需要显式标注——这三者一起构成了 Rust 的"不用 GC 的内存安全"。
& vs &mut
let mut s = Stringfrom;
let r1 = &s; // 不可变借用 (shared reference)
let r2 = &s; // 可以有多个不可变借用
println!; // OK
let r3 = &mut s; // 可变借用: 要求 s declared mut
// let r4 = &s; // ERROR: 已有 &mut, 不能再 &
r3.push;
核心规则——Aliasing XOR Mutation:同一时刻,要么有多个共享引用(只读),要么有恰好一个可变引用(可写),两者不能共存。这条规则防止了数据竞争和 iterator invalidation。
Borrow Checker 的工作方式
编译器在 MIR (Mid-level IR) 上做 borrow checking。每个 borrow 创建时记录:借用了哪个变量,是 shared 还是 mutable,lives until 哪里。
let mut v = vec!;
let first = &v; // immutable borrow of v starts
v.push; // ERROR: mutable borrow of v — first is still live
println!; // first last use
// first's borrow ends here
错误原因:v.push(4) 需要 &mut v,但 first 仍在 scope 中持有 &v。borrow checker 不能允许同时存在 &v 和 &mut v——即使你知道 push 不会影响 v[0],borrow checker 不知道。
Non-Lexical Lifetimes (NLL, 2018 Edition)
NLL 之前,借用的生命周期由 scope 决定(lexical——变量从声明到最后一次出现的 whole block)。NLL 改为由最后一次使用决定:
let mut v = vec!;
let first = &v;
println!; // first 的最后一次使用
// first 的 borrow 在这里结束 (而不是 scope 末尾!)
v.push; // OK: first 已不再 live, borrow 已结束
// 在 NLL 之前, 这无法编译
Reborrow
当传递 &mut T 给函数时,borrow 被"reborrow":
let mut v = vec!;
push; // reborrow: &mut *v → push's &mut v
// push 结束后, reborrow 结束 → v 的 ownership 恢复
// 等价于:
// let reborrow = &mut *v;
// push(reborrow);
// drop(reborrow); ← reborrow 在这里被 drop, v 恢复
Reference 的内存布局
&T 和 &mut T 在运行时就是普通指针(8 bytes on 64-bit)。Borrow checker 所有检查都在编译期,零运行时开销。
let x = 42;
let r = &x; // 汇编: lea rax, [rsp+4]; mov [rsp+8], rax
Fat pointer: &[T] 和 &dyn Trait 是 16 bytes——额外存储 length 或 vtable pointer。
常见陷阱
1. 不能在不可变借用期间修改原值
let mut v = vec!;
let r = &v;
v.clear; // ERROR: &v (immutable) active, can't &mut v
2. Iterator invalidation 被 borrow checker 防止
let mut v = vec!;
for item in &v
3. 函数返回引用——需要显式 lifetime
// 返回的引用借用了 s → 编译器保证 &str 不会比 s 活得更久
参考
- Rust Book: Chapter 4.2 — References and Borrowing
- NLL RFC: RFC 2094
- Polonius: github.com/rust-lang/polonius (next-gen borrow checker)
Keywords: borrow checker, shared reference, mutable reference, NLL, reborrow, aliasing XOR mutation, fat pointer