1069 字
5 分钟
study 3day
2025-11-03

🦀 Rust 所有权与栈/堆内存管理#

目录#

  1. 所有权概念概述
  2. 栈(Stack)
  3. 堆(Heap)
  4. 所有权规则
  5. 移动(Move)与克隆(Clone)
  6. 可变引用与不可变引用
  7. 示例解析
  8. 总结

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)#

堆用于存储 大小在编译时未知或动态变化的数据(如 StringVec 等)。

  • 堆内存分配和释放比较慢
  • Rust 使用所有权规则管理堆内存
  • 当所有者离开作用域时,堆内存会自动释放
fn main() {
let s1 = String::from("Hello"); // 分配堆内存存储字符串
let s2 = s1; // s1 的所有权移动到 s2
// println!("{}", s1); // ❌ 编译错误,s1 已失效
println!("{}", s2); // OK
}

栈 vs 堆总结#

特性栈(Stack)堆(Heap)
数据大小已知固定大小可变大小
分配方式自动动态
访问速度
生命周期作用域结束自动清理所有权结束自动清理
举例i32, bool, f64String, Vec, Box

4️⃣ 所有权规则#

  1. 每个值有且只有一个所有者
  2. 一个值在同一时间只能有一个可变引用,或任意数量的不可变引用
  3. 当所有者离开作用域,内存自动释放
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); // OK

6️⃣ 可变引用与不可变引用#

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️⃣ 总结#

  1. :快速、固定大小、自动释放

  2. :动态大小、受所有权管理、自动释放

  3. 所有权规则

    • 每个值有唯一所有者
    • 移动后原变量失效
    • 借用允许访问但不改变所有权
  4. 引用规则

    • 同一时间可有多个不可变引用
    • 或一个可变引用
  5. 克隆用于堆数据显式复制


这就是 Rust 所有权 + 栈/堆 的核心机制。

💡 练习建议

  1. 创建不同类型变量(i32StringVec)观察栈/堆行为
  2. 尝试移动、克隆、借用,理解编译器报错原因
  3. 结合函数参数传递,理解所有权如何影响函数调用
study 3day
https://iqwq.com/posts/rust/study-3day/
作者
Xiaolin
发布于
2025-11-03
许可协议
CC BY-NC-SA 4.0