第 3 章:所有权和借用
- 作者
- Name
- 青玉白露
- Github
- @white0dew
- Modified on
- Reading time
- 3 分钟
阅读:.. 评论:..
Rust 语言的核心特性之一就是所有权系统。这一系统使得 Rust 程序在编译时就能捕获许多内存错误,确保内存安全和高效。理解所有权、借用和生命周期是掌握 Rust 编程的关键。本章将详细解释这些概念,并通过示例代码和图表帮助你深入理解它们。
什么是所有权
在 Rust 中,每一个值都拥有一个所有者(owner),这个所有者在任何时候都只能有一个。当所有者不再使用这个值时,该值的内存将被释放。这种独特的所有权模型避免了许多常见的内存管理错误,如空悬指针和双重释放。
所有权规则
- 每一个值都有一个所有者。
- 每个值在任一时刻只能有一个所有者。
- 当所有者离开作用域,值会被丢弃。
代码示例
让我们通过一个简单的代码示例来理解所有权:
fn main() { let s1 = String::from("hello"); let s2 = s1; // s1 的所有权转移给了 s2 // 现在 s1 不再有效 println!("{}", s1); // 这行代码会导致编译错误 }
在上面的代码中,s1
的所有权被转移给了 s2
。此后,s1
不再有效,尝试使用 s1
将会导致编译错误。
graph LR A[变量a] -- 所有权转移 --> B[变量b] B -- 所有权转移 --> C[变量c] C -- 所有权转移 --> D[变量d]
借用和引用
在 Rust 中,借用(borrowing)允许你在不转移所有权的情况下使用值。借用通过引用(references)来实现,引用分为可变引用和不可变引用。
不可变引用
不可变引用允许你读取值,但不能修改值。
fn main() { let s1 = String::from("hello"); let len = calculate_length(&s1); println!("The length of '{}' is {}.", s1, len); } fn calculate_length(s: &String) -> usize { s.len() }
在上述代码中,calculate_length
函数借用了 s1
的不可变引用。这种借用是安全的,因为在借用期间,值是不可变的。
可变引用
可变引用允许你修改值,但在任一时间点,只能存在一个可变引用,或者多个不可变引用。
fn main() { let mut s = String::from("hello"); change(&mut s); println!("{}", s); } fn change(some_string: &mut String) { some_string.push_str(", world"); }
在上述代码中,change
函数借用了 s
的可变引用,并且修改了它。
生命周期
生命周期(lifetimes)是 Rust 用来跟踪引用有效性的机制。生命周期注解告诉编译器各种引用之间的关系,有助于避免悬垂引用(dangling references)。
生命周期注解
生命周期注解使用 'a
这样的语法。虽然生命周期注解看起来复杂,但它们通常是编译器在编译时推断的。
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } }
在上述代码中,longest
函数的生命周期注解 'a
指示返回值的生命周期与输入参数的生命周期相关。
图解生命周期
graph LR A[引用a] -- 生命周期'a --> B[引用b] B -- 生命周期'b --> C[引用c] C -- 生命周期'c --> D[引用d]
小结
本章介绍了 Rust 中所有权、借用和生命周期的概念,这些特性是 Rust 内存安全的基础。通过理解和正确使用这些概念,你可以编写出高效且安全的代码。在接下来的章节中,我们将继续深入探索 Rust 的其他高级特性和应用。 【本章节完毕】