所有权机制回顾
先来回顾一下前面的内容:
- Rust的单一所有权机制,让编译器能够准确跟踪所有者的作用域,从而在在所有者超出作用域的时候进行值内存的释放。
- 在同一作用域之下,编译器能够准确判断所有借用(borrow)的使用情况,保证借用的生命周期不会超过值本身的生命周期。
为何需要生命周期标注
尽管单一所有权机制能妥善处理大部分情况。但是,如果将借用(引用)作为函数返回值类型的时候,编译器就不干了:因为缺少足够的信息,无法判断返回的借用是否仍然有效,如果有效那么到何时失效的问题。
也就是说,编译器缺少被借用的值的生命周期信息。
fn max1(x: &i32, y: &i32) -> &i32 {
if x>y {x} else {y}
}
上面的代码编译会报错:缺少具名的生命周期参数。
fn max1(x: &i32, y: &i32) -> &i32 {
---- ---- ^ expected named lifetime parameter
如何标注生命周期
对于返回借用类型缺少生命周期的问题解决,Rust的做法是,对函数返回值进行生命周期参数标注。
返回的借用的生命周期,要么由输入参数的生命周期来标定,要么就是全局静态的(在整个程序运行期间有效),即'static
。
Rust中生命周期参数的格式为:'1到多个小写字母
。
比如,'a
、'input
都是合法的生命周期参数。
输出依赖于输入参数的生命周期
// 输入的两个引用参数具有相同的生命周期参数'a,返回的引用也是
fn max2<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
if x>y {x} else {y}
}
println!("{}", max2(&13,&19));//19
输出为’static
fn lifetime1() -> &'static str {
// 字符串字面量位于ROData区,生命周期是全局静态的
// 详见https://blog.csdn.net/linysuccess/article/details/123765834
let name = "Hello";
// 返回字符串切片
&name[1..]
}
struct中引用类型的标注
写个小例子吧:
struct TreeNode1<'a> {
val: i32,
left: Option<&'a TreeNode1<'a>>,
right: Option<&'a TreeNode1<'a>>,
}
编译器自动标注
事实上,所有引用参数、引用返回值都需要生命周期标注,那为什么很多函数的参数或者返回值都使用了引用,编译器却没有提示我要额外标注生命周期呢?
答案是,编译器会通过一些简单的规则为函数自动添加标注:
- 所有引用类型的参数都有独立的生命周期 'a 、'b 等。
- 如果只有一个引用型输入,它的生命周期会赋给所有输出。
- 如果有多个引用类型的参数,其中一个是 self,那么它的生命周期会赋给所有输出。
总结
函数的引用参数和引用返回值需要生命周期参数进行标注,帮助编译器建立和编译时检查引用之间的生命周期约束关系。
返回引用的生命周期,需要依赖于输入参数的生命周期,或者是整个程序的运行周期(即:静态生命周期'static
)。
编译器根据几条简单的规则对常见情况的引用参数自动进行标注,减轻开发者的负担。