Rust 中级教程 第16课——引用的 lifetime(1)

开篇01本篇文章将介绍 Rust 的 lifetime。lifetime 这也是 Rust 中的重点。简单了解下 Rust 的生命期的概念以及简单使用。本篇文章的阅读时间大约 10 分钟

题外话02文章开头,我建议大家不要将 lifetime 翻译成 生命周期 。其实life circle 这个词组的意思才是 生命周期。来看下lifetime 的有道翻译。

通常我们所说的生命周期应该是存在一个循环过程的。另外,在 Rust 中,只有引用类型才需要标注 lifetime。lifetime 是用来保证引用类型在使用时是有效的,并且在使用结束后释放所占用的内存的一种机制。所以,我们可以将其翻译为引用的生存期,引用的有效期,引用的使用期等等。

lifetime (生命期/有效期)03我们先看一个小例子:

fnmain() {

let a;

{

let b = 1;

a = &b;

}

println!("{}", *a);

}

这段代码是编译不通过的,来看下编译器给出的错误。

字面意思就是 b 活的不够长,很通俗易懂哈哈。简单分析下:变量 a 是一个 &i32 引用类型,我们在内部代码块中初始化 a,但是当内部代码块执行结束后,变量 b 离开作用域被释放了,但是 a 没有被释放,这时 a 就会变成 悬垂指针,当然这在 Rust 中是绝对不允许的。

理论上来讲,其实所有的变量都存在生存期,变量的生命期一定是包含引用的生存期。先来看下面这张图片,红框所示的区域是变量b的生命期。蓝框所示的是a(b的引用)的作用域。很显然b的作用域没有包含a,变量的生命期没有包含引用的生命期,这种做法是禁止的。

我们转换下代码,如下图:

很显然b的作用域包含a,变量的生命期包含了引用的生命期。这段代码是可以正常编译的。

生命期的使用04

标注生命期只有引用类型才需要标注 lifetime。因此,以&i32 为例,标注生命期后变为 &'a i32 ,在 & 后添加 'a,通常叫做生命期 a。a 可以被更换,其命名规则参考变量的命名规则。

&'a i32 标注生命期 a 的共享引用

&'a mut i32 标注生命期 a 的可变引用

函数/方法签名中的生命期标注编译器通常会推断生命期,当然我们也可以标注生命期。通常我们写函数/方法时是下面的写法。

fntest(name: &str) -> &str {

println!("{}", name);

return name;

}

其实,这里是存在生命期标注的,如果编译器可以自动推断生命期时,则无需标注。上面的函数添加生命期标注后如下所示:

fntest_life<'_a>(name: &'_astr) -> &'_astr {

println!("{}", name);

return name;

}

在函数名后面,添加<'a>,如同泛型,在标注前先声明。然后再对每个参数或者返回值标注。

为什么存在生命期?生命期仅用于编译器的检查。并不会更改原有生命期的长短。举个简单的例子,下面的代码是传入两个字符串,返回最长的那个字符串。

fnmain() {

let x = String::from("xxx");

let y = "yyyy";

let z = longest(x, y);

println!("{}", z);

}

fnlongest(x: &str, y: &str) -> &str {

if x.len() > y.len() {

x

} else {

y

}

}

如果我们直接编译,会提示错误。

error[E0106]: missing lifetime specifier

--> src\main.rs:31:33

|

31 | fnlongest(x: &str, y: &str) -> &str {

| ---- ---- ^ expected named lifetime parameter

|

= help: this function'sreturntypecontains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`

help: consider introducing a named lifetime parameter

|

31 | fnlongest<'a>(x: &'astr, y: &'astr) -> &'astr {

| ++++ ++ ++ ++

For more information about this error, try `rustc --explain E0106`.

error: could not compile `lifetime` due to previous error

错误提示告诉我们,缺少生命期标识符。在当编译时期,rust 并不知道我们返回的是 x 还是 y,因此不能确定返回的字符串的生命期。这个函数主体中, if 块返回的是 x 的引用,而 else 块返回的是 y 的引用。所以我们需要标注生命期,来告诉编译器。

fnlongest<'a>(x: &'astr, y: &'astr) -> &'astr {

if x.len() > y.len() {

x

} else {

y

}

}

标注传入参数的生命期都是 a,返回值的生命期也是 a,所以无论返回 x 还是 y,都是生命期 a 的 &str。因此:生命期仅用于编译器的检查。

引用作为函数/方法返回值(接上节)05我们再看下面一个例子,编译会发现报错:

/// 拼接两个字符串

fnconcat_str<'a>(x: &'astr, y: &'astr) -> &'astr {

let s = format!("{}{}",x, y);

return s.as_str();

}

下面是错误,不能返回一个局部变量:

error[E0515]: cannot return reference to local variable `s`

--> src\main.rs:36:12

|

36|return s.as_str();

|^^^^^^^^^^ returns a reference to data owned by the current function

For more information about this error,try `rustc --explain E0515`.

error: could not compile `lifetime` due to previous error我们思考,假设可以通过编译,会发生什么?当函数结束后,s 被释放,返回的引用会变成 悬垂引用,这种做法是在 rust 中禁止的。因此我们可以得出一个结论,当从一个函数/方法返回一个引用时,返回类型的生命期参数需要与其中一个参数的生命期参数相匹配。当然也存在例外,继续往下看。

静态生命期06在 Rust 中,存在一种静态生命期 'static。它表示数据在程序的整个运行期间都有效,它常用于储存全局静态数据和字符串常量。像一些字符串字面量,字节字符串字面量等等这些类似的生命期默认是 'static。在函数里,可以直接返回 'static 的生命期。

fnget_any_str() -> &'staticstr {

return"static";

}

小结07本章仅仅是简单了解下 lifetime,lifetime 是 Rust 中用来保证引用在使用时是有效的。生命期并不会改变在方法和函数中返回引用时,如果返回的引用不指向其中一个参数,那么它必须指向在这个函数中创建的一个值,然而这将会产生悬垂引用。本篇文章写的有些仓促,望大家见谅!

「点点赞赏,手留余香」

赞赏

  • 0人赞过
0
0
0
评论 0 请文明上网,理性发言

相关文章

  • 原文作者:JeffreyM.Perkel虽然学习曲线很陡,但是Rust兼具速度和安全性。2015年,生物信息学家JohannesK?ster还是(用他自己的话说)"差不多全职写Python的"。他当时已经用Python写过一个备受欢迎的工具--流程管理工具Snakemake。现在,他正在准备写的项目所要求的计算能力超过
    鹿雅七 4 3 0 条评论
  • 作者|蔡芳芳 前不久,Rust编程语言的审查团队(ModerationTeam)通过GitHub宣布集体辞职,在技术圈引发了一场关于开源治理的热烈讨论。Rust社区的关注度也随之飙升,相关报道在朋友圈持续刷屏。一位圈内人士对此调侃道:"知道Rust火,没想到能这么火。"上一次Rust获得这么高的关注度,还是2021年初
    mrbai2013 17 3 0 条评论
  • 新智元报道来源:reddit 编辑:小匀 【新智元导读】继AWS、谷歌、华为、微软和Mozilla后,Facebook近日也宣布加入Rust基金会,并承诺将会加大对Rust的采用。这个编程语言最近非常受青睐,相比较C和C++而已更快速、更安全的它,对编写驱动程序和编译器等组件很有吸引力。 近日,Facebook宣布以
    日耳曼蔷薇 6 4 0 条评论
  • 喜欢就关注我们吧!Rust官方博客发布了2020年度的Rust调查报告。 此次调查共收到以14种不同语言完成的8323份回复,使用英语的受访者人数占比最高,为75%,其次是5.4%的中文受访者以及5.3%的俄语受访者。基于此,官方计划从这语言方面改进Rust社区,为那些不希望或无法使用英语的人改善Rust社区状况。 在
    杭州娱乐子龙 8 1 0 条评论
  • 作者|PaulBiggar 译者|弯月,责编|杨碧玉头图|CSDN下载自东方IC 出品|CSDN(ID:CSDNnews)以下为译文: 我们编写了一门语言,其中集合了编程语言、结构化编辑器以及基础设施等所有功能,我们的目标是将构建后端服务的难度降低100倍。我们的这门语言采用了F#,很多人都对此表示很惊讶,包括我在内
    菇凉积 6 3 0 条评论
  • LinusTorvalds发表Rust支持即将出现在Linux内核,并提出首个初始提交应该`包含尽可能少的功能`的要求之后,Rust-for-Linux团队将已开发的部分驱动程序和驱动支持所需的代码裁剪之后,Linus于2022.10.16发布了Linux6.1-rc1开发版本,其中已正式包含Rust相关代码,实现Ru
    带钉的心tlNN 7 1 0 条评论
  • 现有的编程语言非常多,大家都习惯了要在性能、表达力和内存安全之间取舍,直到Rust横空出世。 对于Rust这个新语言,很多人可能都听过,但是没用过。实际上,早从16年起,Rust已经连续六年霸榜,被StackOverflow评选为最受开发者喜爱的语言。数百家科技公司在使用Rust,其中不乏一些世界顶级公司,比如苹果、亚
    lf0ae8 6 3 0 条评论
  • 作者|MikeTang 责编|Aholiab 出品|区块链大本营(blockchain_camp) 2015年5月15日,Rust编程语言核心团队正式宣布发布Rust1.0版本。 4年来,它优雅的解决高并发和高安全性系统问题的能力,受到了越来越多开发者的喜爱。并且连续4年,在StackOverflow开发者「最受喜爱
    xd9304 5 6 0 条评论
  • 作为一门系统编程语言,Rust一直致力于解决高并发和高安全性系统等问题。和老牌的C++相比,Rust的性能也毫不逊色。但曾几何时,因为上手难、用户量少、社区不活跃等诸如问题让想要入门的开发者感到迷茫,如今新的一年已经开始,我们是否真的有必要学习Rust? 作者|NickHeath 译者|虎说 责编|屠敏 出品|CSD
    skyeee 4 0 0 条评论
  • 最近一段时间Rust似乎开始从默默无闻走向聚光灯下,从微软宣布探索采用Rust替代C/C++,到Linux内核维护者表示愿意接受Rust作为驱动开发语言,再到AWS公开表示赞助Rust,同时连续4年被票选为StackOverflow最受欢迎语言的光辉事迹又被搬出来。频频高亮曝光,让"Rust到底能不能成?"、"以后不用
    谔地平线授本 3 1 0 条评论