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);
相关推荐
醉の虾21 分钟前
Vue3 使用v-for 渲染列表数据后更新
前端·javascript·vue.js
张小小大智慧30 分钟前
TypeScript 的发展与基本语法
前端·javascript·typescript
hummhumm39 分钟前
第 22 章 - Go语言 测试与基准测试
java·大数据·开发语言·前端·python·golang·log4j
asleep7011 小时前
第8章利用CSS制作导航菜单
前端·css
hummhumm1 小时前
第 28 章 - Go语言 Web 开发入门
java·开发语言·前端·python·sql·golang·前端框架
幼儿园的小霸王2 小时前
通过socket设置版本更新提示
前端·vue.js·webpack·typescript·前端框架·anti-design-vue
疯狂的沙粒2 小时前
对 TypeScript 中高级类型的理解?应该在哪些方面可以更好的使用!
前端·javascript·typescript
gqkmiss2 小时前
Chrome 浏览器 131 版本开发者工具(DevTools)更新内容
前端·chrome·浏览器·chrome devtools
Summer不秃2 小时前
Flutter之使用mqtt进行连接和信息传输的使用案例
前端·flutter
旭日猎鹰2 小时前
Flutter踩坑记录(二)-- GestureDetector+Expanded点击无效果
前端·javascript·flutter