浅谈 rust 函数的生命周期
一、为什么需要标注生命周期
- 为了避免悬垂引用,也就是函数返回值为引用的时候才需要。
- 假如不需要生命周期标记,例如:
fn main() {
// 需要使用String,因为&str的生命周期是整个程序运行期间
let x = String::from("1111"); // ---------+-- 'a
let long_str; // |
{ // |
let y = String::from("222222"); // -+-- 'b |
long_str = longest(x.as_str(), y.as_str()); // | |
} // -+ |
// |
println!("{}", long_str); // |
} // ---------+
fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() {
x
} else {
y
}
}
编译器在编译上面的代码时不知道longeset
函数返回的是跟x
有关还是跟y
有关,如果跟x
,函数正常运行,但是如果跟y
有关,则程序报错,因为y
的生命周期'b
已经结束了。所以需要加上生命周期
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
二、为什么需要手动标注
可能你会有疑问,那我给每个入参加上'a
不就行了?或者编译器自动加上不就行了?为什么还需要手动标注?实际上,标注了相同的生命周期标注之后,编译器会取其中最短的生命周期去判断。例如:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
println!("{}", y);
x
}
// long_str = longest(x.as_str(), y.as_str());
// ^^^^^^^^^^ borrowed value does not live long enough
此时编译器会报错,但是实际上我们只是打印了y
而已。
三、如何标注生命周期
因此,标注生命周期的方式是返回的引用跟哪些入参有关,就为它们添加相同的生命周期标注
fn longest<'a>(x: &'a str, y: &str) -> &'a str {
println!("{}", y);
x
}
// 222222
// 1111