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

4.5 所有权的转移与所有权规则

所有权系统是 Rust 最独特的特性之一,它使得 Rust 能够在没有垃圾回收器的情况下保证内存安全。理解所有权的转移(Move)以及其背后的规则,是掌握 Rust 内存管理的关键。

4.5.1 所有权规则回顾

在深入所有权转移之前,我们先回顾一下 Rust 的所有权三大规则:

  1. 每个值在 Rust 中都有一个所有者(Owner)。
  2. 同一时间,每个值只能有一个所有者。
  3. 当所有者离开作用域(Scope)时,该值将被丢弃(Drop)。

这些规则是 Rust 内存安全的基础。其中,第二条规则“同一时间,每个值只能有一个所有者”直接引出了所有权转移的概念。

4.5.2 什么是所有权转移

所有权转移(Move)是指将一个值的所有权从一个变量转移给另一个变量的过程。当发生所有权转移时,原来的变量将不再拥有该值,并且不能再被使用。Rust 编译器会阻止你使用已经转移了所有权的变量,从而避免悬挂指针(Dangling Pointer)等问题。

示例:基本类型的所有权转移

对于存储在栈(Stack)上的简单类型,如整数、浮点数、布尔值等,它们实现了 Copy trait。当一个实现了 Copy trait 的值被赋值给另一个变量时,Rust 会进行复制(Copy),而不是转移(Move)。因此,两个变量都拥有各自独立的值。

let x = 5; // 整数类型实现了 Copy trait
let y = x; // 这里发生的是复制,x 的所有权没有转移

println!("x = {}, y = {}", x, y); // 正常编译,x 和 y 都有效

示例:复杂类型的所有权转移

对于存储在堆(Heap)上的复杂类型,如 String、Vec<T> 等,它们没有实现 Copy trait。当它们被赋值给另一个变量时,会发生所有权转移。

let s1 = String::from("hello"); // s1 是 String 的所有者
let s2 = s1; // 所有权从 s1 转移到了 s2

// println!("s1 = {}", s1); // 这行代码会编译错误!s1 已经不再有效
println!("s2 = {}", s2); // s2 现在是该 String 的所有者

在上面的例子中,s1 将内部指向堆内存的指针、长度和容量信息转移给了 s2。为了避免双重释放(double free)错误,Rust 编译器会认为 s1 已经被“移动”了,因此不再允许访问 s1。

4.5.3 所有权转移在函数调用中的应用

所有权转移不仅发生在变量赋值时,也发生在函数参数传递和函数返回值中。

函数参数传递:

当我们将一个值传递给函数时,该值的所有权会转移给函数的参数。函数调用结束后,该值会被释放(除非函数将其返回)。

fn take_ownership(some_string: String) {
    println!("函数内部: {}", some_string);
    // some_string 在此处离开作用域,被 Drop
}

fn main() {
    let s = String::from("hello");
    take_ownership(s); // s 的所有权转移给了函数的 some_string 参数

    // println!("{}", s); // 错误!s 的所有权已经转移
}

函数返回值:

函数可以将值的所有权通过返回值转移回调用者。

fn give_ownership() -> String {
    let some_string = String::from("world");
    some_string // 将 some_string 的所有权返回给调用者
}

fn main() {
    let s1 = give_ownership(); // s1 获得了函数内部创建的 String 的所有权
    println!("{}", s1); // 正常使用
}

4.5.4 所有权转移的规则总结

  1. 对于实现了 Copy trait 的类型(如整数、浮点数、布尔值、字符、包含这些类型的元组),赋值或传参时会发生复制,原变量仍然有效。
  2. 对于未实现 Copy trait 的类型(如 String、Vec<T>、自定义结构体),赋值或传参时会发生转移(Move),原变量失效。
  3. 所有权转移是浅拷贝(Shallow Copy),但 Rust 会自动使原变量失效,从而避免了悬挂指针和双重释放问题。这被称为“移动语义(Move Semantics)”。
  4. 函数参数传递和返回值都会导致所有权的转移。如果你希望函数使用一个值但不获取其所有权,可以使用引用(借用,详见 4.2 节)。

4.5.5 所有权转移的例外:Copy 与 Clone

  • Copy trait:如上所述,实现了 Copy trait 的类型在赋值时会被复制。你可以为你的自定义类型手动实现 Copy trait,但前提是该类型的所有成员都实现了 Copy。
  • Clone trait:对于未实现 Copy 的类型,如果你确实需要深度复制(Deep Copy)堆上的数据,可以调用 .clone() 方法。克隆会显式地复制堆上的数据,因此性能开销较大。
let s1 = String::from("hello");
let s2 = s1.clone(); // 显式克隆,s1 和 s2 都拥有独立的数据

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

4.5.6 小结

所有权转移是 Rust 中一个核心且优雅的设计。它通过编译时的规则,强制程序员清晰地管理内存,从而在编译阶段就消除了数据竞争、悬挂指针等内存安全问题。理解所有权转移,是编写安全、高效的 Rust 代码的基石。在后续的章节中,我们将学习如何通过“借用”来避免不必要的所有权转移,从而编写更灵活、更高效的代码。

Last Updated:: 5/9/26, 3:13 PM