通过对《Rust 程序设计语言》,《通过例子学 Rust 中文版》以及令狐一冲老师对相关知识点的学习总结而成。
rust - 生命周期学习
- 1 生命周期避免了悬垂引用
- 2 借用检查器
- 3 函数中的泛型生命周期
1 生命周期避免了悬垂引用
生命周期的主要目标是避免悬垂引用,它会导致程序引用了非预期引用的数据。
{ /***************** a ****************/let r; /* r的生命周期自从该处定义开始, 到整个a生命周期结束 */{ /***************** b *****************/let x = 5; /* 从x 定义到生命周期b结束为x的生命周期 */r = &x;} /* 在该处x被调用drop方法释放,r对x的引用成为悬垂引用 */println!("r: {}", r);
}
运行之后会提示如下的错误:
rlk@rlk:lifetime$ cargo run Compiling lifetime v0.1.0 (/home/rlk/work/learn_rust/lifetime)
error[E0597]: `x` does not live long enough--> src/main.rs:7:13|
7 | r = &x;| ^^ borrowed value does not live long enough
8 | }| - `x` dropped here while still borrowed
9 |
10 | println!("r = {}", r);| - borrow later used hereFor more information about this error, try `rustc --explain E0597`.
error: could not compile `lifetime` due to previous error
rlk@rlk:lifetime
如上面的错误所指出的,x的生命周期不够长,但是r对x的引用却还一直存在,最终导致了悬垂引用。
2 借用检查器
Rust 编译器有一个 借用检查器(borrow checker),它比较作用域来确保所有的借用都是有效的。
下面是上面的例子,但是更清晰的标注了r和x的生命周期
{let r; // ---------+-- 'a// |{ // |let x = 5; // -+-- 'b |r = &x; // | |} // -+ |// |println!("r: {}", r); // |
} // ---------+
将上面的例子修改为如下所示就可以正常编译运行通过,
{let x = 5; // ----------+-- 'b// |let r = &x; // --+-- 'a |// | |println!("r: {}", r); // | |// --+ |
}
x的生命周期比r长,并且包括了r的生命周期,所以r可以正确的去引用x,当这段代码结束的时候,x和r都会通过drop方法被释放掉,所以也就不会产生悬垂引用的问题。
3 函数中的泛型生命周期
下面我们要实现一个返回两个字符串较长字符串的处理函数。
fn longest(x: &str, y: &str) -> &str {if x.len() > y.len() {x} else {y}
}