1069 字
5 分钟
study 3day
🦀 Rust 所有权与栈/堆内存管理
目录
- 所有权概念概述
- 栈(Stack)
- 堆(Heap)
- 所有权规则
- 移动(Move)与克隆(Clone)
- 可变引用与不可变引用
- 示例解析
- 总结
1️⃣ 所有权概念概述
Rust 通过 所有权系统 来管理内存:
- 每个值在 Rust 中都有一个 所有者(owner)
- 一个值同时只能有 一个所有者
- 当所有者离开作用域时,值会被 自动释放(无需手动
free)
所有权系统保证了内存安全,同时避免了垃圾回收。
fn main() { let s = String::from("Hello"); // s 拥有 "Hello"} // s 离开作用域,内存自动释放2️⃣ 栈(Stack)
栈是 LIFO(后进先出) 数据结构,用于存储固定大小的值。
- 存储在栈上的数据有 已知大小(如整数、布尔、固定数组等)
- 内存分配速度快
- 当变量离开作用域时,自动清理
fn main() { let x = 5; // 整数存储在栈上 let y = x; // 复制一份,x 与 y 独立 println!("x = {}, y = {}", x, y); // OK}栈上数据可以轻松复制,因为大小固定,编译器知道如何拷贝。
3️⃣ 堆(Heap)
堆用于存储 大小在编译时未知或动态变化的数据(如 String、Vec 等)。
- 堆内存分配和释放比较慢
- Rust 使用所有权规则管理堆内存
- 当所有者离开作用域时,堆内存会自动释放
fn main() { let s1 = String::from("Hello"); // 分配堆内存存储字符串 let s2 = s1; // s1 的所有权移动到 s2 // println!("{}", s1); // ❌ 编译错误,s1 已失效 println!("{}", s2); // OK}栈 vs 堆总结
| 特性 | 栈(Stack) | 堆(Heap) |
|---|---|---|
| 数据大小 | 已知固定大小 | 可变大小 |
| 分配方式 | 自动 | 动态 |
| 访问速度 | 快 | 慢 |
| 生命周期 | 作用域结束自动清理 | 所有权结束自动清理 |
| 举例 | i32, bool, f64 | String, Vec, Box |
4️⃣ 所有权规则
- 每个值有且只有一个所有者
- 一个值在同一时间只能有一个可变引用,或任意数量的不可变引用
- 当所有者离开作用域,内存自动释放
fn main() { let s = String::from("Hello");
let r1 = &s; // 不可变引用 let r2 = &s; // 允许多个不可变引用 println!("{} and {}", r1, r2);
// let r3 = &mut s; // ❌ 同一时间不可有可变引用}5️⃣ 移动(Move)与克隆(Clone)
移动(Move)
- 默认情况下,堆数据的赋值会发生 所有权移动
- 移动后原变量不可用
let s1 = String::from("Rust");let s2 = s1; // s1 移动到 s2// println!("{}", s1); // ❌ 编译错误克隆(Clone)
- 如果希望复制堆数据,使用
.clone()
let s1 = String::from("Rust");let s2 = s1.clone(); // 显式复制println!("s1 = {}, s2 = {}", s1, s2); // OK6️⃣ 可变引用与不可变引用
Rust 的借用(Borrowing)机制允许在不转移所有权的情况下访问数据。
let mut s = String::from("Hello");
// 不可变引用let r1 = &s;let r2 = &s;println!("{} and {}", r1, r2);
// 可变引用let r3 = &mut s; // 必须在没有不可变引用时使用r3.push_str(", world!");println!("{}", r3);Rust 编译器保证 数据竞争(Data Race)永远不会发生。
7️⃣ 示例解析
fn main() { let x = 10; // 栈分配 let y = x; // 栈拷贝 println!("x={}, y={}", x, y);
let s1 = String::from("Hello"); // 堆分配 let s2 = s1; // 所有权移动 // println!("{}", s1); // ❌ s1 已失效 println!("{}", s2);
let s3 = s2.clone(); // 显式克隆 println!("s2 = {}, s3 = {}", s2, s3);
// 可变引用 let mut s = String::from("Rust"); let r = &mut s; r.push_str(" language"); println!("{}", r);}8️⃣ 总结
-
栈:快速、固定大小、自动释放
-
堆:动态大小、受所有权管理、自动释放
-
所有权规则:
- 每个值有唯一所有者
- 移动后原变量失效
- 借用允许访问但不改变所有权
-
引用规则:
- 同一时间可有多个不可变引用
- 或一个可变引用
-
克隆用于堆数据显式复制
这就是 Rust 所有权 + 栈/堆 的核心机制。
💡 练习建议:
- 创建不同类型变量(
i32、String、Vec)观察栈/堆行为 - 尝试移动、克隆、借用,理解编译器报错原因
- 结合函数参数传递,理解所有权如何影响函数调用