---
title: 引用与借用
url: https://doc.liz6.com/rust/01-ownership-and-borrowing/02-references-and-borrowing
locale: zh
area: rust
tags:
- rust
- 所有权与借用
date: 2026-06-30
modified: 2026-06-30
description: Rust 借用检查器只认一条规则:同一时刻,要么一个可变引用,要么多个不可变引用,两者不共存(aliasing XOR mutation)。NLL 把检查粒度从词法作用域细化到实际使用区间,reborrow 让嵌套借用不需要显式标注——这三者一起构成了 Rust 的"不用 GC 的内存安全"。
---

# 引用与借用

> Rust 借用检查器只认一条规则:同一时刻,要么一个可变引用,要么多个不可变引用,两者不共存(aliasing XOR mutation)。NLL 把检查粒度从词法作用域细化到实际使用区间,reborrow 让嵌套借用不需要显式标注——这三者一起构成了 Rust 的"不用 GC 的内存安全"。

## & vs &mut

```rust
let mut s = String::from("hello");
let r1 = &s;                         // 不可变借用 (shared reference)
let r2 = &s;                         // 可以有多个不可变借用
println!("{} {}", r1, r2);           // 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 哪里。

```rust
let mut v = vec![1, 2, 3];
let first = &v[0];                   // immutable borrow of v starts
v.push(4);                           // ERROR: mutable borrow of v — first is still live
println!("{}", first);               // 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 改为**由最后一次使用决定**：

```rust
let mut v = vec![1, 2, 3];
let first = &v[0];
println!("{}", first);               // first 的最后一次使用
// first 的 borrow 在这里结束 (而不是 scope 末尾!)

v.push(4);                           // OK: first 已不再 live, borrow 已结束
// 在 NLL 之前, 这无法编译
```

## Reborrow

当传递 `&mut T` 给函数时，borrow 被"reborrow"：

```rust
fn push(v: &mut Vec<i32>) { v.push(5); }

let mut v = vec![1, 2, 3];
push(&mut v);                        // 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 所有检查都在编译期，零运行时开销。

```rust
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. 不能在不可变借用期间修改原值**

```rust
let mut v = vec![1, 2, 3];
let r = &v[0];
v.clear();                           // ERROR: &v (immutable) active, can't &mut v
```

**2. Iterator invalidation 被 borrow checker 防止**

```rust
let mut v = vec![1, 2, 3];
for item in &v {                     // for loop 隐式创建 &v 的借用
    v.push(4);                       // ERROR: &v active, can't &mut v
}
```

**3. 函数返回引用——需要显式 lifetime**

```rust
fn first_word(s: &str) -> &str {     // lifetime elision: actually fn<'a>(s: &'a str) -> &'a str
    &s[..s.find(' ').unwrap_or(s.len())]
}
// 返回的引用借用了 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*
