langShift

所有权与内存模型

深入学习 Rust 的所有权系统、借用规则和内存管理,理解与 JavaScript 垃圾回收的差异

所有权与内存模型

📖 学习目标

理解 Rust 的所有权系统,这是 Rust 最核心的概念。我们将从 JavaScript 的内存管理出发,逐步理解 Rust 如何通过编译时检查确保内存安全。


🎯 内存管理对比

JavaScript 的垃圾回收

JavaScript 使用自动垃圾回收机制:

正在加载...

Rust 的所有权系统

Rust 使用所有权系统在编译时管理内存:

正在加载...

内存管理差异

  1. 自动 vs 手动: JavaScript 自动垃圾回收,Rust 编译时检查
  2. 引用语义: JavaScript 对象通过引用传递,Rust 通过所有权转移
  3. 内存安全: JavaScript 运行时检查,Rust 编译时保证
  4. 性能: JavaScript 有垃圾回收开销,Rust 零成本抽象

🔄 所有权规则

Rust 的所有权规则

Rust 有三个核心所有权规则:

正在加载...

🔗 借用与引用

不可变借用

正在加载...

可变借用

正在加载...

借用规则

正在加载...

📏 生命周期

生命周期注解

正在加载...

🎯 所有权与 JavaScript 对比

数据传递对比

正在加载...

🎯 练习题

练习 1: 所有权转移

分析以下代码,指出哪些地方会发生所有权转移:

fn main() {
let s1 = String::from("hello");
let s2 = s1;
let s3 = s2.clone();
println!("s2: {}", s2);
println!("s3: {}", s3);
}
查看答案
  1. let s2 = s1; - s1 的所有权移动到 s2
  2. let s3 = s2.clone(); - s2 被克隆,s3 获得新数据的所有权
  3. s2 仍然有效,因为 clone 创建了新的数据

练习 2: 借用规则

修复以下代码中的借用错误:

fn main() {
let mut data = vec![1, 2, 3];
let ref1 = &data;
let ref2 = &mut data;
println!("{:?}, {:?}", ref1, ref2);
}
查看答案
fn main() {
let mut data = vec![1, 2, 3];
let ref1 = &data;
let ref2 = &data; // 改为不可变引用
println!("{:?}, {:?}", ref1, ref2);
// 或者先使用不可变引用,再使用可变引用
let mut data = vec![1, 2, 3];
let ref1 = &data;
println!("{:?}", ref1);
let ref2 = &mut data; // 现在可以使用可变引用
ref2.push(4);
println!("{:?}", ref2);
}

练习 3: 生命周期

为以下函数添加正确的生命周期注解:

fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() {
x
} else {
y
}
}
查看答案
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}

📝 总结

在这一章中,我们深入学习了 Rust 的所有权系统:

  1. 所有权规则: 每个值只有一个所有者,所有者离开作用域时值被丢弃
  2. 借用系统: 通过引用借用数据,避免所有权转移
  3. 借用规则: 同一时间只能有一个可变引用或多个不可变引用
  4. 生命周期: 确保引用在有效期内使用
  5. 与 JavaScript 对比: Rust 编译时检查 vs JavaScript 运行时垃圾回收

关键要点

  • 所有权系统是 Rust 内存安全的核心
  • 借用系统允许在不转移所有权的情况下使用数据
  • 生命周期系统确保引用始终有效
  • 这些概念在编译时检查,运行时零开销

常见陷阱

  1. 移动后使用: 值被移动后不能再使用
  2. 同时借用: 不能同时有可变和不可变借用
  3. 悬垂引用: 返回对局部变量的引用
  4. 生命周期不匹配: 引用生命周期不匹配

下一步学习

在下一章中,我们将学习 Rust 的并发和异步编程模型,了解如何安全地处理多线程和异步操作。


继续学习: 并发与异步模型