当前位置: 首页 > news >正文

Rust 生命周期详解 - 实践

Rust 生命周期详解

  • 一、Rust 生命周期详解
    • 1、生命周期的本质
    • 2、基础语法与使用
    • 3、生命周期省略规则
    • 4、高级生命周期模式
    • 5、生命周期与特性(Traits)
    • 6、常见场景与解决方案
    • 7、生命周期错误诊断
    • 8、生命周期与并发
    • 9、最佳实践
  • 二、代码示例

一、Rust 生命周期详解

1、生命周期的本质

2、基础语法与使用

  • 注解格式:撇号后接小写标识符(如'a, 'ctx)。

  • 函数签名示例

    fn longest<
    'a>
    (s1: &
    'a str, s2: &
    'a str) ->
    &
    'a str {
    if s1.len() > s2.len() { s1
    } else { s2
    }
    }
    • 'a 表示输入和输出共享同一生命周期约束。
    • 实际调用时,'as1s2 中较短的生命周期。
  • 结构体中的生命周期

    struct Book<
    'a>
    {
    title: &
    'a str, // 引用字段必须标注生命周期
    }

    结构体实例的生命周期不能超过 title 引用的数据。

3、生命周期省略规则

编译器在以下场景自动推断生命周期(无需显式注解):

  1. 规则 1:每个引用参数分配独立生命周期。
    fn first_word(s: &
    str) ->
    &
    str // 隐式转为: fn first_word<'a>(s: &'a str) -> &'a str
  2. 规则 2:若只有一个输入生命周期,它被赋予所有输出生命周期。
  3. 规则 3:方法中若含 &self&mut self,输出生命周期与 self 绑定。
    impl<
    'a>
    Book<
    'a>
    {
    fn title(&
    self) ->
    &
    str {
    self.title
    } // 自动应用规则3
    }

4、高级生命周期模式

  • 生命周期子类型(Subtyping)

    struct Context<
    's>
    (&
    's str);
    struct Parser<
    'c, 's: 'c>
    {
    context: &
    'c Context<
    's>
    , // 's 必须比 'c 存活更久
    }

    's: 'c 表示 's 至少和 'c 一样长。

  • 泛型中的生命周期约束

    struct Ref<
    'a, T: 'a>
    (&
    'a T);
    // T 必须比 'a 存活更久或为静态类型
  • 静态生命周期 'static

    let s: &
    'static str = "常量字符串";
    // 数据存活整个程序周期

    需谨慎使用:真实 'static 数据极少(如字符串字面量)。

5、生命周期与特性(Traits)

  • 特性对象生命周期

    trait Display {
    /* ... */
    }
    let obj: Box<
    dyn Display>
    ;
    // 默认隐含 'static
    let obj: Box<
    dyn Display + 'static>
    ;
    // 显式标注
  • 高阶生命周期(HRTBs)

    fn apply<
    F>
    (f: F)
    where
    F: for<
    'a>
    Fn(&
    'a i32) // 接受任意生命周期的引用
    {
    let x = 42;
    f(&x);
    }

6、常见场景与解决方案

  • 返回引用:必须绑定到输入参数。

    // 错误:返回局部变量引用
    fn invalid() ->
    &
    str {
    "hello"
    }
    // 正确:返回输入引用
    fn valid<
    'a>
    (s: &
    'a str) ->
    &
    'a str { s
    }
  • 结构体方法:自动应用省略规则。

    impl<
    'a>
    Book<
    'a>
    {
    fn compare(&
    self, other: &
    Book) ->
    &
    str {
    // 编译器自动推断 &self 和 other 的生命周期关系
    }
    }
  • 闭包与生命周期:通常自动推断,但复杂场景需注解:

    let closure = |x: &
    i32, y: &
    i32| ->
    &
    i32 {
    ...
    };
    // 可能需显式标注

7、生命周期错误诊断

  • 典型错误
    let r;
    {
    let x = 5;
    r = &x;
    // 错误:`x` 的生命周期短于 `r`
    }
    println!("{}", r);
  • 解决方案
    1. 缩短引用持有时间。
    2. 延长被引用数据的生命周期(如使用 Rc/Arc)。
    3. 重构代码避免跨作用域引用。

8、生命周期与并发

  • 跨线程传递引用:需满足 'static 或使用作用域线程。
    use std::thread;
    let data = vec![1, 2, 3];
    thread::scope(|s| {
    s.spawn(|| println!("{:?}", data));
    // 安全:线程在 data 有效期内结束
    });

9、最佳实践

  1. 优先依赖编译器推断,仅在必要时显式标注。
  2. 结构体含引用时必须标注生命周期
  3. 避免过度使用 'static,优先考虑所有权转移(如 String 代替 &str)。
  4. 复杂关系使用生命周期子类型'a: 'b)明确约束。

二、代码示例

写一个比较字符串长度的函数:

fn longer(s1: &
str, s2: &
str) ->
&
str {
if s2.len() > s1.len() {
s2
} else {
s1
}
}
fn main() {
let s1 = "Hello";
let s2 = "World!";
let longest: &
str = longer(s1, s2);
println!("The longest string is: {}", longest);
}

这段代码是编译不通过的,编译信息如下:
在这里插入图片描述

PS G:\Learning\Rust\ttt> cargo run
Compiling ttt v0.1.0 (G:\Learning\Rust\ttt)
error[E0106]: missing lifetime specifier
--> src\main.rs:4:34
|
4 | fn longer(s1: &
str, s2: &
str) ->
&
str {
| ---- ---- ^ expected named lifetime parameter
|
= help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `s1` or `s2`
help: consider introducing a named lifetime parameter
|
4 | fn longer<
'a>
(s1: &
'a str, s2: &
'a str) ->
&
'a str {
| ++++ ++ ++ ++
For more information about this error, try `rustc --explain E0106`.
error: could not compile `ttt` (bin "ttt") due to 1 previous error
PS G:\Learning\Rust\ttt>

原因是返回值引用可能会返回过期的引用。此时就需要进行显示的生命周期标注,修改程序如下:

fn longer<
'a>
(s1: &
'a str, s2: &
'a str) ->
&
'a str {
if s2.len() > s1.len() {
s2
} else {
s1
}
}
fn main() {
let s1 = "Hello";
let s2 = "World!";
let longest: &
str = longer(s1, s2);
println!("The longest string is: {}", longest);
}

编译运行:

PS G:\Learning\Rust\ttt> cargo run
Compiling ttt v0.1.0 (G:\Learning\Rust\ttt)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.40s
Running `target\debug\ttt.exe`
The longest string is: World!
PS G:\Learning\Rust\ttt>

加入‘a并不能够改变引用的生命周期,但可以在合适的地方声明两个引用的生命周期一致。返回的引用生命周期要和s1.s2的生命周期一致。

在这里插入图片描述

http://www.wxhsa.cn/company.asp?id=2994

相关文章:

  • 笔记《机器人动力学理论及其应用》上交桂凯博士-中科深谷机器人大讲堂第10期
  • [豪の学习笔记] 软考中级备考 基础复习#9
  • Shiro概述 - 详解
  • 2025CCPC南昌邀请赛游记
  • 双因素认证暴力破解绕过技术解析(2023更新版)
  • 文本三剑客
  • 软件工程第二次作业-个人项目
  • Git 分支
  • 用 Go 打造一个服务器资源指标采集器:结合 Prometheus Exporter 实战
  • 2025年API安全建设方案最佳实践:七步五方法
  • 【数学】拉格朗日乘数法
  • 华为芯片之父,33年默默开拓,铸就“中国芯”,功成身退时却鲜有人知!
  • Redis为什么适合做分布式锁? - 浪矢
  • 百度昆仑芯高调出圈:对标寒武纪,估值或达千亿港元?
  • WPS 定制版
  • 2024年以来,数学领域已有多位在国外顶尖高校取得终身教职的学者回国
  • 685.冗余连接
  • form表单和表单控件
  • 阿里云OSS图片生成缩略图和获取视频的封面方法
  • VSCode 运行 Python
  • [mysql] 卸载
  • 树上问题
  • 突发!美国将复旦微等23家中国实体列入“实体清单”
  • [GenAI] Function Calling
  • form表单
  • 【Zotero7】使用Attanger和百度同步空间如何进行同步?
  • XSS 漏洞挖掘学习
  • str
  • 到底该用 KPI 还是 OKR ?
  • 【重点!!!】必知必会必须掌握的serializers序列化器类之Serializer和ModelSerializer核心区别