生命周期(lifetime)
- 动态语言 vs rust
- 悬垂指针(dangling reference)
- 内存释放
- drop(free)
- 垃圾回收
fn main() {
let x_ref = {
let x = 3;
&x
};
// x_ref would now refer to `x`, but `x` is out of scope, so x_ref is dangling.
println!("{}", x_ref)
}
创建生命周期
在 Rust 中,生命周期主要通过生命周期注解来创建和使用。生命周期注解是一种显式声明引用有效时间的方式,通常用 'a
、'b
这样的符号表示。
示例:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
在这个示例中,longest
函数接受两个字符串切片参数,并返回其中一个更长的字符串切片。'a
生命周期注解表明返回值的生命周期与输入参数的生命周期相同。
生命周期类别
fn:
fn example<'a>(input: &'a str) -> &'a str { input }
struct:
struct Example<'a> { part: &'a str, }
enum:
enum StringOption<'a> { Some(&'a str), None }
生命周期消除(Lifetime Elision)
rust 编译器自动推理,无需手动重复添加
- 每个引用参数都有自己的生命周期参数。
- 如果只有一个输入引用参数,那么它的生命周期会被赋予所有输出引用。
- 如果有多个输入生命周期参数,但其中一个是
&self
或&mut self
,那么self
的生命周期会被赋予所有输出引用。
fn first_word(s: &str) -> &str {
&s[..1]
}
// 返回值不包含引用,无需标注
fn add(a: &i32, b: &i32) -> i32 {
*a + *b
}
// 只包含一个 引用 生命周期一致
fn identity(a: &i32) -> &i32 {
a
}
特殊生命周期标注
'static
生命周期表示整个程序运行期间都有效的生命周期。这通常用于全局变量或字符串字面量。
let s: &'static str = "hello";
const SOME_COORDINATE: (i32, i32) = (7, 4);
let static_reference: &'static (i32, i32) = &SOME_COORDINATE;
struct Counter<'a> {
counter: &'a mut i32
}
impl Counter<'_> {
fn increment(&mut self) {
*self.counter += 1;
}
}
生命周期约束
生命周期注解可以用来约束多个引用之间的关系。
fn example<'a, 'b>(x: &'a str, y: &'b str) -> &'a str
where
'b: 'a,
{
x
}
在这个示例中,'b: 'a
表示生命周期 'b
必须不短于 'a
。
生命周期子类型和协变
生命周期可以有子类型关系,较短的生命周期可以被视为较长生命周期的子类型。这在协变(covariance)中尤为重要。
fn example<'a, 'b>(x: &'a str, y: &'b str) -> &'a str
where
'a: 'b,
{
x
}
小试牛刀
fn test_lifetime_mut() {
fn insert_value<'a, 'b>(my_vec: &mut Vec<&'a i32>, value: &'b i32) {
my_vec.push(value);
}
{
let x = 1;
let mut my_vec = vec![&x];
let y = 2;
insert_value(&mut my_vec, &y);
println!("{my_vec:?}");
}
}
课后习题
Requirements: 修改如下代码,使得编译通过,并解释为什么?
进阶: 还有几种解法可以实现,你能通过修改一个生命周期参数实现吗?
fn test_lifetime_multiple() {
fn insert_value<'a, 'b>(my_vec: &'a mut Vec<&'a i32>, value: &'b i32) {
my_vec.push(value)
}
let mut my_vec: Vec<&i32> = vec![];
let val1 = 1;
let val2 = 2;
let a = &mut my_vec;
insert_value(a, &val1);
println!("a is {:?} ", a);
let b = &mut my_vec;
insert_value(b, &val2);
println!("b is {:?}", b);
println!("{my_vec:?}");
}