0、引入
Rust 生命周期机制是与所有权机制同等重要的资源管理机制,之所以引入这个概念主要是应对复杂类型系统中资源管理的问题。
引用是对待复杂类型时必不可少的机制,毕竟复杂类型的数据不能被处理器轻易地复制和计算。但引用往往导致极其复杂的资源管理问题,首先认识一下垂悬引用(在Rust所有权文章提到这个概念):
let r;
{
let x = 5;
r = &x;
} //出来这个范围,其实X已经被释放,所以r就是垂悬引用
//引用必须在值的生命周期以内才有效。
println!("r: {}", r);
再看一个函数的例子:
//定义一个函数,注意函数参数使用的是引用
fn longer(s1: &str, s2: &str) -> &str {
if s2.len() > s1.len() {
s2
} else {
s1
}
}
fn main() {
let r;
{
let s1 = "rust";
let s2 = "ecmascript";
r = longer(s1, s2);
}
println!("{} is longer", r);
}
//上述的例子是编译不通过,因为但 r 被使用的时候源值 s1 和 s2 都已经失效了
//改为 String就可以
fn longer(s1: String, s2: String) -> &str {
if s2.len() > s1.len() {
s2
} else {
s1
}
}
1、生命周期注释
- 生命周期注释是描述引用生命周期的办法。
- 虽然这样并不能够改变引用的生命周期,但可以在合适的地方声明两个引用的生命周期一致。
- 生命周期注释用单引号开头,跟着一个小写字母单词。
如下所示
&i32 // 常规引用
&'a i32 // 含有生命周期注释的引用
&'a mut i32 // 可变型含有生命周期注释的引用
改写上述代码:
//注意我们需要用泛型声明来规范生命周期的名称
fn longer<'a>(s1: &'a str, s2: &'a str) -> &'a str {
if s2.len() > s1.len() {
s2
} else {
s1
}
}
fn main() {
let r;
{
let s1 = "rust";
let s2 = "ecmascript";
r = longer(s1, s2);
println!("{} is longer", r);
}
}
运行结果:ecmascript is longer
2、结构体中使用字符串切片引用
代码如下(示例):
fn main() {
struct Str<'a> {
content: &'a str
}
let s = Str {
content: "string_slice"
};
println!("s.content = {}", s.content);
}
运行结果:s.content = string_slice
3、静态生命周期
- 生命周期注释有一个特别的:'static ;
- 所有用双引号包括的字符串常量所代表的精确数据类型都是 &'static str ,'static
所表示的生命周期从程序运行开始到程序运行结束。
4、泛型、特性与生命周期协同作战
感受一下下面的程序,是不是蒙蔽,哈哈,早晚用上,现在可以不理解,只要眼熟就行。
use std::fmt::Display;
fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str
where T: Display
{
println!("Announcement! {}", ann);
if x.len() > y.len() {
x
} else {
y
}
}
5、总结
Rust的生命周期其实和所有权有着关系,变量在超过表示的范围就会自动释放,不管你是在堆或者栈上都帮你主动释放,所以在写程序的时候要注意。
文章评论