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
    }
}

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

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

这我们将str1str2、返回值的生命周期都设置为'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);
相关推荐
啦啦右一几秒前
前端 | MYTED单篇TED词汇学习功能优化
前端·学习
半开半落5 分钟前
nuxt3安装pinia报错500[vite-node] [ERR_LOAD_URL]问题解决
前端·javascript·vue.js·nuxt
理想不理想v32 分钟前
vue经典前端面试题
前端·javascript·vue.js
不收藏找不到我34 分钟前
浏览器交互事件汇总
前端·交互
YBN娜1 小时前
Vue实现登录功能
前端·javascript·vue.js
阳光开朗大男孩 = ̄ω ̄=1 小时前
CSS——选择器、PxCook软件、盒子模型
前端·javascript·css
minDuck1 小时前
ruoyi-vue集成tianai-captcha验证码
java·前端·vue.js
小政爱学习!1 小时前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
魏大帅。1 小时前
Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
前端·javascript·ajax