前置

需要理解变量生命周期。

显式标注的特点

不改变引用的生命周期,描述多个生命周期的关系

显式标注的意义和作用

给编译器提示,帮助编译器判断所写的代码是否安全(避免悬垂引用)。

<==>描述函数输入参数和输出参数的关系以帮助编译器检查所写的代码是否符合预期

<==>编译器根据函数的标注对函数调用时的传参情况判断。(限制函数的调用处于安全)

<==>确切的说是当用户添加显式标注时表达了用户对此函数输入输出引用参数的生命周期的期待,编译器根据用户的期待与相关变量的实际生命周期对比以判断是否满足。

<==>其实编译器都知道,主要是反过来提示用户注意此代码是否为安全的。

例子和说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
fn longest<'a>(x: &'a str,y: &'a str) -> &'a str {
// 'a是xy中较小的那个(以保证安全) 假设返回的那个引用拥有最短的生命周期以保证安全
if x.len() > y.len() {
x
} else {
y
}
}
// main 1
fn main() {
let str1 = String::from("hello");
let result;
{
let str2 = String::from("world");
// result的生命周期是较短的即str2,此时在离开此作用域后调用println宏时
// 的result是不能保证未被释放,因此报错。
result = longest(&str1, &str2);
}
println!("The longest string is {}", result);
}
// main 2
fn main() {
let str1 = String::from("hello");
{
let str2 = String::from("world");
let result = longest(&str1, &str2);
// 即使result是较短的那个生命周期(str2),但仍然在str2的作用域内调用,因此可保证安全。
println!("The longest string is {}", result);
}
}

​ 对于实际运行中,longest函数的返回值的生命周期是不定的(可能和x,y任意一个相同)。因此我们当我们在调用longest函数的地方时,为保证返回的引用总是安全(未被清理)的,即假设返回的引用仅仅拥有x,y变量中较短的那个生命周期。若如此情况下,在调用处仍旧满足返回的引用是安全的即可保证返回的引用总是安全的。(试想,若我们返回的引用的生命周期即使是x,y中生命周期较短的那个,仍然是安全的。那么当返回的引用在另一种情况下即拥有更长的生命周期时将必定是安全的)。此时再回头看代码中的注释是否更清楚呢?