Open linbuxiao opened 1 year ago
生命周期的存在是 Rust 对于程序运行保守态度的结果。 如果一个函数传入了两个引用,并返回了其中一个引用(或者返回值与其中一个引用是相关的),Rust 就会报错。 因为它困惑于返回值的生命周期,返回值的生命周期与函数接受变量作用域息息相关,Rust 无法判断当前的返回值是否合法。 而是否合法又与悬垂指针相关,这是编译器无法容忍的。 所以你必须事先声明参数与返回值的生命周期,以供 check。 例如:
fn max_num(x: &i32, y: &i32) -> &i32 {
if x > y {
&x
} else {
&y
}
}
fn main() {
let x = 1; // -------------+-- x start
let y = 8; // -------------+-- y start
let max = max_num(&x, &y); // -------------+-- max start
println!("max: {}", max); // |
} // -------------+-- max, y, x over
你会收到错误信息 missing lifetime specifier
。即使 x 与 y 的生命周期肉眼可见的一致,但从函数 max_num 的角度看,这两者的生命周期仍然是不确定的。
以避免是如下情况:
fn max_num<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
if x > y {
&x
} else {
&y
}
}
fn main() {
let x = 1; // -------------+-- x start
let max; // -------------+-- max start
{ // |
let y = 8; // -------------+-- y start
max = max_num(&x, &y); // |
} // -------------+-- y over
println!("max: {}", max); // |
} // -------------+-- max, x over
在这种情况下,我们得到了适当的报错:`y
does not live long enough`。
这归功于我们认真书写了生命周期。为自己鼓掌吧。
任何类型声明在完善之后都会具有复杂度。这似乎是难以避免的。就连生命周期也难逃此劫。 首先我们拿出上面的例子:
fn max_num<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
if x > y {
&x
} else {
&y
}
}
问题来了,如果 x 与 y 的生命周期并不完全一致,那么这里的 'a
意味着什么?
保守的结果,选最短的那个。
那如果这里确实存在多个生命周期,如何表达呢?
生命多个就可以了,如下:
fn max_num<'a, 'b: 'a>(x: &'a i32, y: &'b i32) -> &'a i32 {
if x > y {
&x
} else {
&y
}
}
当然,如果多个生命周期只是看起来不一样也就失去了意义。
例如这里的写法'b: 'a
,就表示 a 的生命周期不能超过 b。被框住了。
存在的意义
生命周期存在于函数层面,即使我们在定义结构或者字面量时都可以进行声明,但它的意义停留在函数层面。 比如下面的例子:
对于例子 1 的结构体而言,如果我们引用的 v 生命周期短于 Foo 本身,
cargo check
会在静态检查时得出报错。 但这不代表这个结构体是错的,只是对于它的函数调用来说,这是不合理的。 总而言之,生命周期的定义是为了函数更好的被调用。