Rust第十节(下) - 生命周期

10.3 生命周期

Rust中的生命周期主要是用来解决悬垂引用的问题。首先我们来看看Rust中的悬垂引用问题怎么产生的。

10.3.1 悬垂引用

以下这个例子,我们在模块外声明了一个变量r,然后在模块给他赋值w的引用,但是模块里面的内容执行完就会销毁掉里面的内容,造成r变量指向一个空指针 ,形成了悬垂引用,如下:

rust 复制代码
 let r;                             //----------'a
{                                   //        |
    let w = String::from("stephen");//-----'b |
    r = &w;                         //  |     |
}                                   //---     | 
println!("{}", r);                  //--------+
// 值比变量的声明的范围小,造成悬垂引用

通过上面例子来看,当我们声明的变量比值的生命周期更长时,这个时候就会触发悬垂引用。那么Rust是怎么检测出来的呢?

10.3.2 生命周期标注规则

Rust有一个专门处理引用数据的检查器,叫借用检查器。它负责Rust整个生命周期的检查。

接下来我们就来了解一下生命周期的标注规则,我们一般使用' + 小写字母来表示一个生命周期,例如: 'a, 'b等等。

当我们需要配合着&使用,我们就需要在后面再加一个空格,例如:

rust 复制代码
&str // 引用
&'a str // 带有生命周期标注的引用
&'a mut str  // 带有生命周期标注的可变引用

10.3.3 省略规则

在实践之前,我们再来了解一下,借用检查机器内置的一些省略规则: 输入生命周期 类似 函数传参 输出生命周期 类似 函数返回值

第一条: 每个传入的参数都一个生命周期,传入一个参数有一个输入生命周期,传入两个参数则有两个生命周期

第二条: 如果只有一个参数,那么输出生命周期和输入生命周期相同

第三条: 在结构体 和枚举 的方法中,当拥有多个输入生命周期参数,而其中一个是&self或&mut self时,self的生命周期会被赋予给所有的输出生命周期参数。

10.3.4 函数添加生命周期标注

接下来我们尝试写一个比较两段字符串长度的函数,例如:

rust 复制代码
 fn longest(str1: &str, str2: &str) -> &str {
    if str1.len() > str2.len() {
        str1
    } else {
        str2
    }
}

但是因为这里传入的str1和str2的引用,我们并不知道他们的生命周期、什么时候会销毁,所以这里返回值,很有可能是一个悬垂引用,所以会编译失败。 我们来给他添加生命周期,保证引用的值比函数后面销毁,例如:

rust 复制代码
fn longest<'a>(str1: &'a str, str2: &'a str) -> &'a str {
    if str1.len() > str2.len() {
        str1
    } else {
        str2
    }
}

这我们将str1和str2、返回值的生命周期都设置为'a,然后就通过借用检查器的编译了。

10.3.5 结构体添加生命周期标注

我们在之前的结构体章节里面定义一个了一个User结构体,如下:

rust 复制代码
struct User {
    name: String,
}

当时我们没有使用&str,因为我们还没有设计到生命周期的概念,现在我们使用&str来代替这个name字段,例如:

rust 复制代码
struct User<'a> {
    name: &'a str,
}

10.3.7 静态生命周期

我们还可以在Rust中定义一个特别的生命周期'static,它只作用于字符串字面量,并且它作用于小程序从周期开始到结束,例如:

rust 复制代码
let str1: &'static str = "stephen";
println!("{}", str1);

注意 我们要慎用这个静态类型,它不仅会增加存储的时间周期、增加内存的消耗,作用于全局还会绕过借用检查器的规则。

10.3.8 泛型,特征,生命周期结合使用

最后,让我们来写一个泛型,特征,生命周期结合的函数结束第10节的学习。我们来改造改造之前的longest函数,如下:

rust 复制代码
fn longest<'a, T>(str1: &'a str, str2: &'a str, str3: T) -> &'a str
where
    T: Display,
{
    println!("extra={}", str3);
    if str1.len() > str2.len() {
        str1
    } else {
        str2
    }
}
let s1 = String::from("stephen");
let s2 = String::from("james");
let long = longest(&s1, &s2, 2);
println!("{}", long);
相关推荐
陈随易7 小时前
bm2,Node.js 与 Bun 项目部署新选择
前端·后端·程序员
福兮说9 小时前
canvas 旋转图片的六个坑:四角被裁、Math.ceil 多出 1px 黑边、JPG 角发黑、翻转方向反了
前端·javascript·图像处理·canvas
传人once10 小时前
多图片上传预览功能如何写
前端·css·html·jquery·html5
Eric.4610 小时前
Wan‑Animate+MiniMax-H3 本地部署 AI 漫剧流水线:8G 显存动作迁移与动态分镜工程实战
前端·人工智能·comfyui·ai漫剧
库拉镜像AI牛牛12 小时前
短剧内容自动化生产:知漫剧工作室落地教程
大数据·服务器·前端·人工智能·语音识别
律宏阔12 小时前
Flutter 列表图片内存优化:CachedNetworkImage 与 ClipRRect 的取舍
前端·flutter
行者全栈架构师12 小时前
【鸿蒙心迹】相册文搜图工程化落地:HarmonyOS 7.0 端侧 AI 检索全链路实战与 5 个踩坑解法
前端
律宏阔12 小时前
Dart 3 Record:解决 Future.wait 异构返回值的类型问题
前端·flutter
Seraphina3612 小时前
DVWA(XSS Reflected/Stored High,CSRF Low)
前端·xss·csrf
默_笙13 小时前
🍔 中间件不只是打日志:四个钩子、一次短路,和自带的工具
前端·javascript