3.1 所有权规则与栈/堆内存模型

Rust 的所有权系统是一套在编译期强制执行的规则,用于管理程序如何使用内存。它不需要垃圾回收器,也不依赖程序员手动调用 free,而是通过静态分析确保内存安全。要理解所有权,首先需要了解 Rust 如何在内存中存储数据,尤其是栈(stack)和堆(heap)的区别。

栈与堆

栈是一种后进先出(LIFO)的数据结构,存取速度快,但大小在编译时必须已知且固定。所有基本类型(如整数、布尔值、字符等)都存储在栈上。

堆则用于存储在运行时才能确定大小或生命周期不确定的数据。访问堆上的数据比栈慢,因为需要通过指针间接访问,并涉及内存分配和释放操作。

例如,String 类型在栈上保存指向堆中实际字符串内容的指针、长度和容量信息,而真正的文本数据则存放在堆上。

所有权的基本规则

Rust 的所有权系统基于以下三条核心规则:

  1. Rust 中的每个值都有一个被称为其所有者(owner)的变量。
  2. 值在任意时刻只能有一个所有者。
  3. 当所有者离开作用域时,该值将被自动丢弃(调用 drop 函数),释放其占用的资源。

这些规则共同保证了内存不会被重复释放,也不会发生泄漏。

作用域与资源释放

变量的作用域从其声明处开始,到当前代码块结束为止。当变量离开作用域时,Rust 会自动调用 drop 清理资源。

{
    let s = String::from("hello"); // s 进入作用域
    // 使用 s
} // s 离开作用域,drop 被调用,堆内存被释放

这种“资源获取即初始化”(RAII)模式是系统编程中管理资源的经典方法,Rust 将其作为语言核心机制。

示例:所有权转移

考虑以下代码:

let s1 = String::from("hello");
let s2 = s1;
// println!("{}", s1); // 错误:s1 不再有效

s1 被赋值给 s2 时,所有权从 s1 转移到 s2s1 不再可用。这是为了防止两个变量同时拥有同一堆内存的所有权,从而避免双重释放(double free)错误。

这种行为与栈上数据(如整数)不同,后者默认会被复制而非移动。我们将在下一节详细讨论移动与复制的区别。

小结

所有权规则结合栈/堆内存模型,构成了 Rust 内存安全的基础。通过在编译期追踪每个值的所有者及其生命周期,Rust 能够在不牺牲性能的前提下,消除大量常见的内存错误。理解这些基本概念,是掌握后续借用、引用和生命周期机制的前提。

#Rust 入门教程 分享于 1 周前

内容由 AI 创作和分享,仅供参考