Rust基础

第5课:所有权与借用

🎯 本课目标

深入理解Rust核心机制——所有权系统,掌握移动、复制、借用和引用规则。

⚠️ 这是Rust最重要的概念!所有权系统是Rust区别于所有语言的核心。务必反复阅读直到完全理解。

1. 所有权三规则

  1. Rust中每个值都有一个所有者
  2. 同一时刻,值只能有一个所有者
  3. 当所有者离开作用域,值被丢弃(drop)

2. 移动语义

fn main() {
    let s1 = String::from("hello");
    let s2 = s1;  // 移动!s1不再有效
    // println!("{}", s1);  // ❌ 编译错误
    println!("s2 = {}", s2);

    // 对比:Copy trait
    let x = 5;
    let y = x;  // 复制!x仍有效
    println!("x={}, y={}", x, y);
}

✅ 编译验证通过

移动的内存模型

let s1 = String::from("hello"); 栈 堆 ┌──────────┐ │ s1 │ ┌───┬───┬───┬───┬───┐ │ ptr ─────────→│ h │ e │ l │ l │ o │ │ len: 5 │ └───┴───┴───┴───┴───┘ │ cap: 5 │ └──────────┘ let s2 = s1; // 移动! 栈 堆 ┌──────────┐ │ s1 │ ┌───┬───┬───┬───┬───┐ │ (已失效) │ ✗ │ h │ e │ l │ l │ o │ └──────────┘ ✗ └───┴───┴───┴───┴───┘ ✗ ↑ ┌──────────┐ ✗ │ │ s2 │ │ │ ptr ─────────────────┘ │ len: 5 │ │ cap: 5 │ └──────────┘ s1被标记为无效,不会二次释放堆内存

3. Clone深拷贝

fn main() {
    let s1 = String::from("hello");
    let s2 = s1.clone();  // 深拷贝
    println!("s1={}, s2={}", s1, s2);  // ✅ 都有效
}

✅ 编译验证通过

Clone的内存: 栈 堆 s1 ──────→ "hello" ← 原始 s2 ──────→ "hello" ← 新分配的副本!

4. Copy trait

实现Copy的类型在赋值时自动复制:

fn main() {
    let x: i32 = 42;    // i32: Copy
    let y = x;           // 复制
    let arr = [1,2,3]; // [i32;3]: Copy
    let arr2 = arr;      // 复制

    let s = String::from("hi");  // String: 非Copy
    let s2 = s;                      // 移动!
}

✅ 编译验证通过

5. 引用与借用

5.1 不可变引用

fn calculate_length(s: &String) -> usize {
    s.len()  // 借用,不获取所有权
}

fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);
    println!("'{}' 长度 {}", s1, len);
}

✅ 编译验证通过

5.2 可变引用

fn append_world(s: &mut String) {
    s.push_str(", world");
}

fn main() {
    let mut s = String::from("hello");
    append_world(&mut s);
    println!("{}", s);  // "hello, world"
}

✅ 编译验证通过

5.3 借用规则

在同一时刻:

绝不能同时!

fn main() {
    let mut s = String::from("hello");
    let r1 = &s;        // ✅
    let r2 = &s;        // ✅
    // let r3 = &mut s;  // ❌ 已有不可变引用
    println!("{} {}", r1, r2);

    let r3 = &mut s;    // ✅ NLL允许
    println!("{}", r3);
}

✅ 编译验证通过

6. 悬垂引用防止

fn dangle() -> &String {
    let s = String::from("hello");
    &s   // ❌ 返回局部变量的引用
}

// 正确:返回所有权
fn no_dangle() -> String {
    String::from("hello")
}

📝 练习题

练习1:修复错误

let s1 = String::from("hello");
let s2 = s1;
println!("{}, world!", s1);  // ?

练习2:字符串反转

写函数接受&mut String,原地反转。

练习3:所有权追踪

追踪process(s)后s的所有权变化。

🏆

成就解锁:所有者

理解所有权系统——无GC内存安全的核心

🔬 深度理解:Rust的设计哲学

Rust的设计遵循几个核心原则,理解这些原则能帮助你更好地使用Rust:

1. 显式优于隐式

Rust要求你显式声明可变性(mut)、生命周期、错误处理。没有隐式类型转换、没有隐式异常传播、没有隐式GC。虽然代码更冗长,但行为更可预测。

2. 编译期检查优于运行时检查

借用检查器、生命周期分析、trait约束——所有这些都在编译期完成。这意味着运行时零开销。你付出的代价是编译时间,换来的是运行时性能和安全。

3. 零成本抽象

高层抽象(泛型、trait、迭代器、async/await)编译后与手写底层代码一样高效。你不需要在抽象和性能之间做选择。

4. 所有权是核心

所有其他特性——借用检查、生命周期、并发安全——都建立在所有权模型之上。理解所有权,就理解了Rust。

📖 Rust发展历史

年份里程碑
2006Graydon Hoare开始Rust项目
2009Mozilla开始赞助
2010首次公开
2012第一个预发布版
2015Rust 1.0发布
2016-2024连续Stack Overflow最受喜爱语言
2022Linux内核接纳Rust
2023Android、Windows开始使用Rust
2024Rust基金会成立,生态系统成熟
2026你正在学习Rust!

💡 学习路径建议

基础阶段(1-2周):完成本课程第1-7课,重点理解所有权和借用。

进阶阶段(2-3周):完成第8-14课,掌握trait、泛型、智能指针。

系统阶段(2-3周):完成第15-21课,实际写并发程序。

网络阶段(2-3周):完成第22-28课,构建真实的网络服务。

实战阶段(持续):完成第29-35课,开始自己的项目。


📚 扩展阅读

以下资源帮助你深入学习本课主题:

🔑 关键术语回顾

本课涉及的核心概念,确保你理解每一个:

术语说明
所有权Rust内存管理的核心机制,每个值有唯一所有者
借用通过引用访问数据,不获取所有权
生命周期引用有效的范围,编译期分析工具
traitRust的接口/抽象机制,类似其他语言的接口
泛型参数化类型,零成本抽象
模式匹配强大的数据解构和分支机制
零成本抽象高层抽象不引入运行时开销
fearless concurrency编译器保证线程安全

💬 学习建议

  1. 动手编码 — 每个代码示例都在本地运行一遍
  2. 修改实验 — 故意改错代码,看编译器报什么错
  3. 完成练习 — 每课的练习题是巩固知识的关键
  4. 阅读源码 — 看标准库和优秀开源项目的实现
  5. 写项目 — 真正掌握需要构建真实项目

🤔 常见问题

Q: Rust学习曲线真的很陡吗?

A: 前期确实需要适应所有权和借用检查器,但一旦理解了,这些概念会让你的代码更可靠。大多数人2-4周就能上手。

Q: Rust适合什么项目?

A: 系统编程、Web服务、CLI工具、嵌入式、WASM、网络服务、数据库等。基本上需要性能和安全的地方都适合。

Q: 遇到编译错误怎么办?

A: Rust编译器的错误信息非常友好!仔细阅读,通常会指出问题所在和修复建议。也可以用cargo clippy获取更多提示。