Rust —— 生命周期
生命周期(Lifetime)是 Rust 中确保引用有效性的机制。每个引用都有生命周期,即引用保持有效的作用域。大多数情况下生命周期是隐式推断的,但在某些情况下需要显式标注。
1. 生命周期的作用
1.1 防止悬垂引用
1 | fn main() { |
编译器会阻止这段代码,因为 x 在使用 r 之前就被销毁了。
1.2 借用检查器
Rust 的借用检查器比较引用的生命周期,确保所有引用都是有效的。
1 | fn main() { |
2. 函数中的生命周期标注
2.1 为什么需要标注
1 | fn longest(x: &str, y: &str) -> &str { // ❌ 缺少生命周期标注 |
编译器无法确定返回的引用是 x 还是 y,因此无法判断返回引用的生命周期。
2.2 生命周期标注语法
1 | &i32 // 引用 |
生命周期参数名称:
- 以
'开头 - 通常使用小写字母
'a是最常用的名称
2.3 函数签名中的生命周期
1 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { |
含义: 返回值的生命周期与参数中较短的生命周期相同。
2.4 使用示例
1 | fn main() { |
1 | fn main() { |
3. 结构体中的生命周期
3.1 定义包含引用的结构体
1 | struct ImportantExcerpt<'a> { |
含义: ImportantExcerpt 实例的生命周期不能超过 part 字段引用的数据。
4. 生命周期省略规则
编译器使用三条规则自动推断生命周期:
每个引用参数都有自己的生命周期
1
2
3fn foo(x: &str) -> &str
// 等同于
fn foo<'a>(x: &'a str) -> &'a str如果只有一个输入生命周期,赋予所有输出生命周期
1
fn first_word(s: &str) -> &str
如果是方法且有多个输入生命周期,其中之一是
&self或&mut self,那么self的生命周期赋予所有输出生命周期
4.1 示例
1 | // 不需要标注 |
5. 方法中的生命周期
1 | struct ImportantExcerpt<'a> { |
6. 静态生命周期
'static 表示引用在整个程序期间都有效:
1 | let s: &'static str = "I have a static lifetime."; |
使用场景: 字符串字面量、全局变量。
警告: 不要滥用 'static,大多数情况下问题在于尝试创建悬垂引用。
7. 泛型、Trait 和生命周期结合
1 | use std::fmt::Display; |
总结
- 生命周期标注:描述引用之间的关系,不改变实际生命周期
- 借用检查器:确保所有引用在使用时都是有效的
- 省略规则:大多数情况下编译器可以自动推断
- 结构体生命周期:包含引用的结构体需要标注生命周期
- ‘static:整个程序期间有效的引用
生命周期是 Rust 确保内存安全的重要机制,虽然初学时可能感到困惑,但理解后能帮助我们编写更安全的代码。
Hooray!生命周期学习完成!!!