Tailwind CSSTailwind CSS
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • 搜索未来:SEO与GEO双引擎实战手册
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • Rust 开发入门
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain
Home
  • Tailwind CSS 书籍目录
  • Vue 3 开发实战指南
  • React 和 Next.js 学习
  • TypeScript
  • React开发框架书籍大纲
  • Shadcn学习大纲
  • Swift 编程语言:从入门到进阶
  • SwiftUI 学习指南
  • 函数式编程大纲
  • Swift 异步编程语言
  • Swift 协议化编程
  • SwiftUI MVVM 开发模式
  • SwiftUI 图表开发书籍
  • SwiftData
  • ArkTS编程语言:从入门到精通
  • 仓颉编程语言:从入门到精通
  • 鸿蒙手机客户端开发实战
  • WPF书籍
  • C#开发书籍
learn
  • 搜索未来:SEO与GEO双引擎实战手册
  • Java编程语言
  • Kotlin 编程入门与实战
  • /python/outline.html
  • Rust 开发入门
  • AI Agent
  • MCP (Model Context Protocol) 应用指南
  • 深度学习
  • 深度学习
  • 强化学习: 理论与实践
  • 扩散模型书籍
  • Agentic AI for Everyone
langchain

2.3 Rust的所有权系统

所有权系统是 Rust 最独特、最核心的特性。它是一套由编译器在编译时检查的规则,用于管理内存和其他资源,从而无需垃圾回收器(GC)即可保证内存安全。理解所有权是掌握 Rust 的关键。

所有权规则

在 Rust 中,所有权系统遵循以下三条核心规则:

  1. 每个值在 Rust 中都有一个被称为其所有者的变量。
  2. 同一时间,一个值只能有一个所有者。
  3. 当所有者离开作用域时,该值将被丢弃(内存被释放)。

作用域与所有权

作用域是程序中一个项(item)有效的范围。当变量进入作用域时,它变得有效;当它离开作用域时,其拥有的资源会被自动释放。

{                      // s 在这里无效,它尚未声明
    let s = String::from("hello"); // s 从这里开始有效
    // 使用 s
}                      // 此作用域已结束,s 不再有效,其内存被自动释放

在这个例子中,s 的所有者就是变量 s 本身。当代码块结束时,s 离开作用域,Rust 会自动调用一个特殊的函数 drop 来释放 s 所指向的堆内存。这被称为资源获取即初始化(RAII)。

移动(Move)

对于存储在堆上的复杂数据类型(如 String、Vec),赋值或传参默认会移动所有权,而不是进行深拷贝。

let s1 = String::from("hello");
let s2 = s1; // s1 的所有权被移动到 s2

// println!("{}", s1); // 错误!s1 不再有效,因为其所有权已被移动
println!("{}", s2); // 正确,s2 现在是所有者

为什么 s1 会失效?因为 String 由三部分组成:指向堆内存的指针、长度和容量。当 s2 = s1 时,Rust 复制了这些栈上数据,但 s2 的指针指向了与 s1 相同的堆内存。为了避免在 s1 和 s2 离开作用域时两次释放同一块内存(双重释放错误),Rust 认为 s1 不再有效。这种操作被称为“移动”。

相比之下,对于存储在栈上的简单类型(如整数、布尔值),赋值会进行复制,因为它们的拷贝成本很低。

let x = 5;
let y = x; // x 仍然有效,因为 i32 实现了 Copy trait
println!("x = {}, y = {}", x, y);

克隆(Clone)

如果我们确实需要深度复制堆上的数据,可以使用 clone 方法。

let s1 = String::from("hello");
let s2 = s1.clone(); // 深拷贝堆内存

println!("s1 = {}, s2 = {}", s1, s2); // 两者都有效

clone 会显式地复制堆内存,因此 s1 和 s2 各自拥有独立的内存,可以同时有效。

函数与所有权

将值传递给函数与赋值类似,会发生移动或复制。

fn main() {
    let s = String::from("hello");
    takes_ownership(s); // s 的所有权被移动到函数中
    // println!("{}", s); // 错误!s 已失效

    let x = 5;
    makes_copy(x); // x 是 i32 类型,实现了 Copy,所以 x 仍然有效
    println!("{}", x); // 正确
}

fn takes_ownership(some_string: String) {
    println!("{}", some_string);
} // 这里 some_string 离开作用域,内存被释放

fn makes_copy(some_integer: i32) {
    println!("{}", some_integer);
} // 这里 some_integer 离开作用域,无特殊操作

函数的返回值也可以转移所有权。

fn main() {
    let s1 = gives_ownership(); // 返回值所有权被移动到 s1
    let s2 = String::from("hello");
    let s3 = takes_and_gives_back(s2); // s2 所有权被移动,返回值所有权被移动到 s3
}

fn gives_ownership() -> String {
    let some_string = String::from("yours");
    some_string // 返回 some_string,所有权移出函数
}

fn takes_and_gives_back(a_string: String) -> String {
    a_string // 返回 a_string,所有权移出函数
}

所有权与内存安全

所有权系统通过编译时检查,从根本上解决了以下内存安全问题:

  • 悬垂指针:当所有者离开作用域后,其内存被释放,其他指针无法再访问该内存,因为所有权规则保证了只有所有者才能释放内存。
  • 双重释放:同一块内存只能被其所有者释放一次,因为所有权只能被移动,不能复制。
  • 缓冲区溢出:Rust 的数组和向量在运行时进行边界检查,防止越界访问。

总结

所有权系统是 Rust 管理内存的基石。它通过一套严格的规则,在编译时确保内存安全,无需垃圾回收器。理解“移动”、“克隆”以及作用域的概念,是编写安全、高效的 Rust 代码的第一步。在后续章节中,我们将学习“借用”和“引用”,它们提供了在不转移所有权的情况下访问数据的能力,进一步扩展了所有权的灵活性。

Last Updated:: 5/9/26, 2:49 PM