定制app开发【Rust指南】生命周期机制


文章目录

  前言

   生命周期机制是与所有权定制app开发机制同等重要的资源管理机制,定制app开发之所以引入这个概念主定制app开发要是应对复杂类型系统定制app开发中资源管理的问题。定制app开发引用是对待复杂类型时定制app开发必不可少的机制,毕竟在Rust 定制app开发中复杂类型的数据不能定制app开发被处理器轻易地复制和计算。但是为什么还有引入的概念呢,这是因为引用常常会导致非常复杂的资源管理问题。


1、所有权中的垂悬引用解析

先来看一下垂悬引用中所有权的变化:

{    let ans;    {        let x = 5;        ans = &x;    }    println!("ans: {}", ans);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这段代码是不会通过 Rust编译器的,原因是 ans 所引用的值已经在使用之前被释放,
borrowed value does not live long enough意为x有效时间太短。

红色区域为 ans的生命周期,绿色区域为 x的生命周期,很显然绿色区域比红色区域小得多,引用必须在值的生命周期以内才有效。

2、结构体中使用String 而不用&str 的原因

用一个函数 longer 解释:

fn longer(s1: &str, s2: &str) -> &str {    if s2.len() > s1.len() {        s2    } else {        s1    }}fn main() {    let r;    {        let s1 = "rust";        let s2 = "ecmascript";        r = longer(s1, s2);    }    println!("{} is longer", r);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

longer 函数取 s1s2 两个字符串切片中较长的一个返回其引用值。

这段代码不会通过编译,原因是返回值引用可能会返回过期的引用:

这段程序中虽然经过了比较,但 r 被使用的时候源值 s1 和 s2 都已经失效了。当然我们可以把 r 的使用移到 s1 和 s2 的生命周期范围以内防止这种错误的发生。

对于函数来说,它并不能知道自己以外的地方是什么情况,它为了保障自己传递出去的值是正常的,必须遵循所有权原则消除一切危险,所以 longer 函数并不能通过编译。

3、生命周期注释

生命周期注释是描述引用生命周期的办法,虽然这样并不能够改变引用的生命周期,但可以在合适的地方声明两个引用的生命周期一致。

生命周期注释用单引号开头,跟着一个小写字母单词:

&i32        // 常规的引用&'a i32     // 含有生命周期注释的引用&'a mut i32 // 可变型含有生命周期注释的引用
  • 1
  • 2
  • 3

让我们用生命周期注释改造 longer 函数:

fn longer<'a>(s1: &'a str, s2: &'a str) -> &'a str {    if s2.len() > s1.len() {        s2    } else {        s1    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

我们需要用泛型声明来规范生命周期的名称,函数返回值的生命周期将与两个参数的生命周期一致

fn main() {    let r;    {        let s1 = "rust";        let s2 = "ecmascript";        r = longer(s1, s2);        println!("{} is longer", r);    }}运行结果:ecmascript is longer
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

注意:

Rust 自动推导类型的能力很强,如果上面的s1、s2不是字符串切片类型,而是字符串类型的话 r得到的值会在{} 执行完后通过 drop 自动清理掉。

4、结构体中使用字符串切片引用

之前的文章中说过结构体中也是可以使用字符串切片的,那么了解过生命周期的知识后就可以具体设计一个示例了:

fn main() {    struct Str<'a> {        content: &'a str    }    let s = Str {        content: "string_slice"    };    println!("s.content = {}", s.content);}//运行结果:s.content = string_slice
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

如果对结构体 Str 有方法定义:

impl<'a> Str<'a> {    fn get_content(&self) -> &str {        self.content    }}
  • 1
  • 2
  • 3
  • 4
  • 5

这里返回值并没有生命周期注释,早期 Rust 不支持生命周期自动判断,所有的生命周期必须严格声明,但主流稳定版本的 Rust 已经支持了这个功能,因此可以不加注释。

5、静态生命周期

生命周期注释有一个特别的:'static
所有用双引号包括的字符串常量所代表的精确数据类型都是 &'static str
'static 所表示的生命周期从程序运行开始到程序运行结束,就相当于其他语言中的静态全局变量。

6、泛型、特性与生命周期综合使用

函数如下:

use std::fmt::Display;fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str    where T: Display{    println!("Announcement! {}", ann);    if x.len() > y.len() {        x    } else {        y    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

这段程序出自 《Rust 圣经》,是一个同时使用了泛型特性生命周期 机制的程序,大家可以体验一下 Rust 这种巧妙的组合,先有个体验,到后面的学习中肯定会用到。


本篇博客复习了前期所有权知识中的引用机制,补充了结构体使用字符类型切片的遗留问题,介绍了生命周期机制并有综合案例讲解。到此 Rust 两大资源管理机制学习完毕,欢迎大家的订阅学习!

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发