本页目录
所有权模型
Rust 的所有权模型只有三条规则:每个值有唯一所有者、所有者离开作用域时值被 drop、赋值和传参会转移所有权(move)。Copy 是 move 的例外(位复制后两个变量都可用),Clone 是显式深拷贝,partial move 让你从结构体中搬走部分字段。这三条规则是 Rust 不用 GC 却能保证内存安全的根基。
为什么 Rust 需要所有权
C 的手动 malloc/free 和 C++ 的 RAII 都依赖程序员纪律——忘记释放、double free、use-after-free 在编译期完全不可见。GC 语言自动管理但引入运行时开销和 stop-the-world 延迟。Rust 的答案:在编译期通过所有权规则保证内存安全,零运行时开销。
核心三条规则:
- Rust 中每个值有且仅有一个 owner(所有者)
- owner 离开作用域时,值被 drop
- 赋值/传参/返回值会转移(move)所有权,除非类型实现了 Copy
Move Semantics
let s1 = Stringfrom;
let s2 = s1; // s1 的所有权移动到 s2
// println!("{}", s1); // ERROR: s1 已被 move, 不能再使用
String 在栈上存储 3 个 word(指针、长度、容量),实际数据在堆上。let s2 = s1 是浅拷贝(复制栈上的 3 个 word),然后标记 s1 失效——不会发生 double free,因为只有 s2 会在作用域结束时调用 drop 释放堆内存。
编译器实际生成的伪代码:
s1 = String { ptr → heap[5 bytes "hello"], len: 5, cap: 5 }
s2 = String { ptr → same heap, len: 5, cap: 5 } // move: 复制栈上字段
s1 被标记为 "moved out" → drop(s1) 被编译器跳过
Copy 与 Clone
let x = 42;
let y = x; // x 仍然可用 — i32 实现了 Copy
println!; // OK
Copy trait 是编译器自动识别的标记——实现了 Copy 的类型在赋值时是 bitwise copy 而非 move。条件是:类型中的所有字段都必须实现了 Copy。i32、bool、char、&T 实现了 Copy;String、Vec<T>、Box<T> 没有——因为它们有堆数据。
Clone 是显式的深拷贝:.clone() 由程序员调用,可以分配新的堆内存。String 实现了 Clone 但没有 Copy——显式 .clone() 产生新的 String,不会发生所有权转移。
let s1 = Stringfrom;
let s2 = s1.clone; // 深拷贝: 新的 heap allocation
println!; // 两个独立的 String, 都有效
Move 发生的位置
// 1. 赋值
let s2 = s1; // move
// 2. 传参
// s 获得所有权
take; // s1 move into s → s1 失效
// 3. 返回值
// 所有权随返回值转移给 caller
// 4. 模式匹配
let = ; // 两个 Vec 分别 move 到 a 和 b
// 5. 闭包捕获
let v = vec!;
let closure = ; // 闭包 captured v by move (因为 Vec 不实现 Copy)
// v 不能再被外部使用!
Stack 数据 vs Heap 数据
理解 move 和 copy 的关键:栈上的数据 bitwise copy 是安全的——所有权转移只需要复制栈上内容。堆数据的所有权转移也只需要复制栈上的指针,堆上的数据不复制。
let s1 = String::from("hello"); // stack: [ptr|len|cap], heap: "hello"
let s2 = s1; // stack copy: [same ptr|same len|same cap]
// s1 标记 moved → drop(s1) 不调用
// 作用域结束: drop(s2) → 释放 heap 上的 "hello"
Copy 的条件
什么类型自动实现了 Copy?
- 所有字段都实现了 Copy
- 没有实现 Drop(如果有 Drop,说明有资源需要释放——不能是简单的 bitwise copy)
// 手动 derive Copy (需 also Clone)
// 所有字段都 Copy → Point 也是 Copy
; // String 不 Copy → MyString 不 Copy
// 不能 derive Copy for MyString!
部分移动 (Partial Move)
let p = ;
let = p; // s 获得了 String 的所有权, n copy 了 42
// println!("{:?}", p); // ERROR: p.0 已被 move
println!; // OK: p.1 是 i32, Copy 了, 仍在 p 中
Drop 顺序
作用域结束时,变量按声明的逆序被 drop:
// drop(b) → drop(a)
这对安全性很重要——后面的变量可能引用前面的变量,先 drop 后面的保证了引用始终有效。
参考
- Rust Book: Chapter 4.1 — What is Ownership
- Rust Reference: destructors, move semantics
- RFC: RFC 213 (default Move semantics)
Keywords: ownership, move, Copy, Clone, stack, heap, drop, partial move, RAII