Rust 生命周期
首先每个引用都有生命周期,也就是引用保持有效的作用域
一个引用的作用域从声明的地方开始一直持续到最后一次使用为止
let a=String::from("a");
let b=&a;//b的诞生 ,后续没有在使用b,所以b死亡
在借用者生命期间,所有者必须是活的,不然就会产生悬垂引用,幸运的是我们不用关注它,交给编译器来提示,编译器通过生命周期来检查
大部分时候生命周期是隐含并可以推断的,但有些情况就无法推断了,需要程序员自己指出
fn longest(x: &String, y: &String) -> &String {//这个函数会报错,具体原因我们后面会讲到
if x.len() > y.len() {//可以理解成随机返回 x 或 y,因为在运行时2种情况都会出现
x
} else {
y
}
}
fn main() {
let a=String::from("a");
let c;
{
let b=String::from("b");
c = longest(&a,&b);//我们并不知道它会返回a还是b,这导致生命周期的不确定性,那么此时c就是不安全的,你不敢在大括号外使用c
}
}
下面是修改后
fn longest<'a>(x: &'a String, y: &'a String) -> &'a String {//统一生命周期,按照最小生命周期来分析
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let a=String::from("a");
let c;
{
let b=String::from("b");
c = longest(&a,&b);
println!("{}",c);//安全
}//b在这里就死了
// println!("{}",c);//这行会报错,因为最小生命周期是b
}
注意:
生命周期声明类似于变量类型声明,不会改变对象的真正生命周期。当你生命的生命周期和实际不符合的时候,编译器会报错。
函数或方法的参数的生命周期被称为 输入生命周期,而返回值的生命周期被称为 输出生命周期
隐式生命周期,官方介绍了3条规则
- 每一个是引用的参数都有它自己的生命周期参数
- 如果只有一个输入生命周期参数,那么它被赋予所有输出生命周期参数
- 如果方法有多个输入生命周期参数并且其中一个参数是 &self 或 &mut self, 那么所有输出生命周期参数被赋予 self 的生命周期
你应该意识到了,其实都是隐式存在生命周期的,上面只不过是编辑器无法分析,要求我们显式声明
fn f(x:&i32){}
fn f<'a>(&'a i32){}
fn f2(x:&String)->&String{}
fn f2<'a>(x:&'a String)->&'a String{}
//为什么返回值一定是'a ,因为如果是函数内部的所有者,那么返回出去的借用者就是 悬垂引用,因为在退出函数时 那个所有者就死了
//所以当 参数们只有一个生命周期时,那么返回值也一定是那个生命周期
fn f3(x:&i32,y:&i32,...){}
fn f3<'a,'b,...>(x:&'a i32,y:&'b i32,...){}
//再多参数也是这样,没必要显式声明,咱就懒点
fn f4<'a,'b>(x:&'a String,y:&'b String) -> &'a String {
// &String::from("") //报错,生命周期不是'a
// &y //报错,原因同上
&x
}
关于第三条,特别说明一下
impl ABC {//如果ABC 是一个加工用的对象,那么就不应该返回&self的生命周期
fn f1(&self,a:&String)->&String{//返回的生命周期是&self的
a //报错因为生命周期不同
}
fn f2<'a>(&self,a:&'a String)->&'a String{//但是可以这样
a
}
}
生命周期语法是用于将函数的多个参数与其返回值的生命周期进行关联的。一旦他们形成了某种关联,Rust 就有了足够的信息来允许内存安全的操作并阻止会产生悬垂指针亦或是违反内存安全的行为
结构体定义
struct ABC<'a>{
A:&'a i32
}
impl<'a> ABC<'a> {
fn f1(x:&'a i32){}
fn f2(&self,x:&'a i32){}
}
struct ABCD<'a>{//一样
A:&'a i32,
B:&'a i32
}
struct ABCDE<'a,'b>{//不一样
A:&'a i32,
B:&'b i32
}
静态生命周期
'static
其生命周期能够存活于整个程序期间
不过将引用指定为 'static 之前,思考一下这个引用是否真的在整个程序的生命周期里都有效。你也许要考虑是否希望它存在得这么久,即使这是可能的。大部分情况,代码中的问题是尝试创建一个悬垂引用或者可用的生命周期不匹配,请解决这些问题而不是指定一个 'static 的生命周期
白话说就是 它是否真的可以存活整个程序期间,不是靠'static
,而是这个引用是否真实可以存活,前面提到:生命周期声明类似于变量类型声明,不会改变对象的真正生命周期
,所以’'static’只是告诉编译器而已
所有的字符串字面值(&str)都拥有 'static
生命周期
生命周期声明是入参和返回值或者结构体成员之间的一种生命周期约定和限制
参考:
官方文档
知乎 - Rust生命周期