Rust 中两种 static 生命周期标注的区别
本文介绍了 Rust 中的两种 static 生命周期标注: T: 'static 和 T: &'static, 它们是有本质区别的。
Rust 中的 static 生命周期标注
Rust 中有的 static 生命周期意味着该类型的生命周期同整个程序的生命周期相同,意味着编译器会认为它一直是有效的。
在 Rust 中,有两种使用 static 生命周期标注的方法:
- 一种是类型本身的生命周期为 static:
T: 'static
. - 另一种是,该类型指向的数据的生命周期为 static:
T: &'static
.
它们之间是有本质区别的。
T: ‘static
它表示规定 T 类型本身的生命周期是是 static 的。
use std::fmt::Display;
fn main() {
static_bound("a static str"); // OK
}
// 'static 要求 T 类型的可以在 'static 生命周期内使用
fn static_bound<T: Display + 'static>(t: T) {
println!("{}", t);
}
这是 OK 的,因为 static_bound 的参数要求生命周期必须为 static,而字符串字面值的生命周期正好符合。
但是下面的写法是错误的:
use std::fmt::Display;
fn main() {
{
let a_str = "a string".to_string();
// 通过引用传递,生命周期依赖于 a_str 的作用域
// 然而 a_str 的作用域不是整个程序(static)
static_bound(&a_str); // OK
}
}
// 'static 要求 T 类型的可以在 'static 生命周期内使用
fn static_bound<T: Display + 'static>(t: T) {
println!("{}", t);
}
a_str
的生命周期不是 static,而 static_bound
要求 T 类型的生命周期必须为 static,所以编译报错,提示 a_str
存活的不够长。
T: ‘&static
我们将 static_bound
的参数列表改一下 (t: &T)
,表示T的引用的内容的生命周期是 static,此时编译通过。
use std::fmt::Display;
fn main() {
{
let a_str = "a string".to_string();
// 通过引用传递,生命周期依赖于 a_str 的作用域
// 然后 a_str 的作用域不是整个程序(static)
static_bound(&a_str); // OK
}
}
// 'static 要求 T 类型的可以在 'static 生命周期内使用
fn static_bound<T: Display + 'static>(t: &T) {
println!("{}", t);
}
这是因为 &'static
不管类型本身的生命周期,它只在乎引用所指向的内存中的数据是否在整个程序运行中存在。
那么 &a_str
指向一个字符串字面值,它一定在整个程序运行中存在,所以编译通过,它不在乎引用本身的作用域。
总结
通过上述例子可以看到:
T: 'static
在乎的是 T 类型本身的生命周期,也就是 T 类型本身的作用域;T: &'static
在乎的是 T 类型指向的数据的作用域。
在一般代码实践中,应该避免使用 T: &'static
,因为这表明,即使 T 类型的作用域不是整个程序运行周期,编译器也会使其通过编译,就如第三个例子。
然而在遇到难以解决的生命周期的问题的时候,可以适当使用 T: 'static
使程序通过编译,使编译器理解我们的意思,不再阻拦我们。
最后修改于 2024-12-01