所有权与内存模型
深入学习 Rust 的所有权系统、借用规则和内存管理,理解与 JavaScript 垃圾回收的差异
所有权与内存模型
📖 学习目标
理解 Rust 的所有权系统,这是 Rust 最核心的概念。我们将从 JavaScript 的内存管理出发,逐步理解 Rust 如何通过编译时检查确保内存安全。
🎯 内存管理对比
JavaScript 的垃圾回收
JavaScript 使用自动垃圾回收机制:
正在加载...
Rust 的所有权系统
Rust 使用所有权系统在编译时管理内存:
正在加载...
内存管理差异
- 自动 vs 手动: JavaScript 自动垃圾回收,Rust 编译时检查
- 引用语义: JavaScript 对象通过引用传递,Rust 通过所有权转移
- 内存安全: JavaScript 运行时检查,Rust 编译时保证
- 性能: 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);}
查看答案
let s2 = s1;
- s1 的所有权移动到 s2let s3 = s2.clone();
- s2 被克隆,s3 获得新数据的所有权- 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 的所有权系统:
- 所有权规则: 每个值只有一个所有者,所有者离开作用域时值被丢弃
- 借用系统: 通过引用借用数据,避免所有权转移
- 借用规则: 同一时间只能有一个可变引用或多个不可变引用
- 生命周期: 确保引用在有效期内使用
- 与 JavaScript 对比: Rust 编译时检查 vs JavaScript 运行时垃圾回收
关键要点
- 所有权系统是 Rust 内存安全的核心
- 借用系统允许在不转移所有权的情况下使用数据
- 生命周期系统确保引用始终有效
- 这些概念在编译时检查,运行时零开销
常见陷阱
- 移动后使用: 值被移动后不能再使用
- 同时借用: 不能同时有可变和不可变借用
- 悬垂引用: 返回对局部变量的引用
- 生命周期不匹配: 引用生命周期不匹配
下一步学习
在下一章中,我们将学习 Rust 的并发和异步编程模型,了解如何安全地处理多线程和异步操作。
继续学习: 并发与异步模型