1. Rust生命周期(lifetime)是什么?
在 Rust 中,生命周期(Lifetime)是指一个变量或借用的有效时间范围。它指定了一个变量或借用在何时被创建,以及它在何时不再存在。Rust 中的每个变量或借用都有一个生命周期,它必须在其有效时间范围内被使用。如果一个变量或借用的生命周期结束了,那么它将不能再被访问,否则会引发编译时错误。生命周期通常由 Rust 中的编译器自动管理,开发者不需要手动管理生命周期。但是,开发者可以通过使用 Rust 的生命周期语法来指定生命周期,以实现更加精细的内存管理。
说明:
- 生命周期结束,变量和借用生命周期结束
- 生命周期由Rust自己掌管,开发人员无需手动管理
划重点:
- Rust 中的每一个引用都有其 生命周期(lifetime),也就是引用保持有效的作用域。大部分时候生命周期是隐含并可以推断的,正如大部分时候类型也是可以推断的一样。
例子:
fn mxsm(x: &str) -> &str {
x
}
上面的例子生命周期隐藏了。
2.生命周期(lifetime)标注
生命周期标注并不改变任何引用的生命周期的长短。与当函数签名中指定了泛型类型参数后就可以接受任何类型一样,当指定了泛型生命周期后函数也能接受任何生命周期的引用。生命周期标注描述了多个引用生命周期相互的关系,而不影响其生命周期。
生命周期参数名称必须以撇号('
)开头,其名称通常全是小写,类似于泛型其名称非常短。'a
是大多数人默认使用的名称。生命周期参数标注位于引用的 &
之后,并有一个空格来将引用类型与生命周期标注分隔开。
说明:
- 'static 是Rust内置的生命周期,相当于关键字。
- 生命周期标注告诉 Rust 多个引用的泛型生命周期参数如何相互联系的
2.1 变量生命周期标注
生命周期标注语法:
&i32 //引用默认
&'a i32 //带有显示生命周期
&'a mut i32 // 带有显式生命周期的可变引用
2.2 函数签名中的生命周期标注
fn mxsm_fn(x: &str, y: &str) -> &str { //在开发工具中会直接提示报错
if x.len() > y.len() {
x
} else {
y
}
}
通过函数签名标注生命授权来消除编译错误:
fn mxsm_fn y.len() {
x
} else {
y
}
}
2.3结构体定义中的生命周期标注
struct mxsm{
name: &str, //开发工具直接报错 缺少生命周期
name_t: String //没有错误
}
从上面的代码可以验证一句话:Rust 中的每一个引用都有其 生命周期,有的时候被省略了而已。
结构体定义生命周期标注语法:
struct mxsm {
fn mxsm_fn(&self)->i32{
3
}
fn mxsm_ts(&self, tt:&str) -> &str{
self.st
}
}
2.5 Trait生命周期边界
语法:
Syntax
TypeParamBounds :
TypeParamBound ( + TypeParamBound )* +?
TypeParamBound :
Lifetime | TraitBound
TraitBound :
?? ForLifetimes? TypePath
| ( ?? ForLifetimes? TypePath )
LifetimeBounds :
( Lifetime + )* Lifetime?
Lifetime :
LIFETIME_OR_LABEL
| 'static
| '_
特征(Trait)和生命周期界限为泛型项目(generic item)提供了一种限制其参数类型和生命周期的方法。可以在 where 子句中为任何类型提供边界。对于某些常见情况,也有更简短的形式:
- 在声明通用参数之后编写边界:
fn f() {}
与fn f() where A: Copy {}
相同。 - 在特征声明中作为超特征(supertrait):
trait Circle: Shape {}
等同于trait Circle where Self: Shape {}
。 - 在特征声明中作为关联类型的边界:
trait A { type B: Copy; }
等同于trait A where Self::B: Copy { type B; }
。
在使用项目时,项目的边界必须得到满足。在对泛型项目进行类型检查和借用检查时,边界可用于确定类型是否实现了某个特征。例如,对于 Ty: Trait
:
- 在泛型函数的主体中,可以对
Ty
值调用来自Trait
的方法。同样,可以使用Trait
上的关联常量。 - 可以使用来自
Trait
的关联类型。 - 可以使用带有
T: Trait
边界的泛型函数和类型,并将Ty
用于T
。
3. 生命周期省略
函数或方法的参数的生命周期被称为 输入生命周期(input lifetimes),而返回值的生命周期被称为 输出生命周期(output lifetimes)。
生命周期省略的三条规则:
每一个是引用的参数都有它自己的生命周期参数
fn mxsm_fn(x: &'a str, y: &'b str)
fn mxsm_fn1 &i32
fn mxsm &'a i32
上面代码等同
如果方法有多个输入生命周期参数并且其中一个参数是 &self
或 &mut self
,那么所有输出生命周期参数被赋予 self
的生命周期
说明:方法第一个参数是**&self**
或
&mut self ,说明是对象的方法。
4.静态生命周期
'static
,其生命周期能够存活于整个程序期间。 所有的字符串字面量都拥有 'static
生命周期,如下面例子:
let mxsm:&'static str = "mxsm world";
4.1 'static 生命周期省略
常量和静态引用类型的声明都隐式地具有’static’生命周期,除非明确指定生命周期。
const STRING: &str = "bitstring"; //生命周期省略
const STRING: &'static str = "bitstring"; //显示生命周期
如果静态或常量项包括函数或闭包引用,而这些引用本身又包括引用,则编译器将首先尝试标准省略规则。如果它无法通过其通常的规则解决生命周期
// Resolved as `fn &'a str`.
const RESOLVED_SINGLE: fn(&str) -> &str = |x| x;
// Resolved as `Fn usize`.
const RESOLVED_MULTIPLE: &dyn Fn(&Foo, &Bar, &Baz) -> usize = &somefunc;
5.总结
Rust 的生命周期机制是一种确保代码正确性和安全性的重要机制。通过理解 Rust 的生命周期概念,开发者可以编写更加可靠和安全的代码。
我是蚂蚁背大象,文章对你有帮助给项目点个❤关注我GitHub:mxsm,文章有不正确的地方请您斧正,创建ISSUE提交PR~谢谢! Emal:mxsm@apache.com