生命周期
生命周期是为引用服务;还记得我们讲引用时原则吗?
- 引用生效期间 不应该超过 被引用变量的有效期,否则使用引用指向的内存 是无效的
- 在引用使用某个变量期间,变量不能被转移
- 在共享引用使用期间(生效时),不能被修改 也不能有可变引用
- 在可变引用生效期间 ,变量不能有其他引用
本节要探讨的问题是:
- RUST是如何知道引用什么时候生效 什么时候不生效的?
- 在什么情况 我们需要明确告诉编译器 某个引用的生命周期?
概念讲解
作用域: 作用域指某个变量的可见区间,当变量离开作用域之后会被销毁
//离开作用域之后 变量不可见
fn main() {
let a = 10;
{
let a_ref = &a;
}
println!("{}",a_ref); //cannot find value `a_ref` in this scope
}
借用检查器: RUST 编译器在编译阶段,会检查每个引用变量 引用的内存的有效性 防止引用无效内存
fn main() {
let a_ref: &i32;
{
let a:i32 = 10;
a_ref = &a;
}
println!("a_ref {}",a_ref);
}
当然,也会检查同一块内存 是否被多个引用使用,以及是否否和多个引用的约束
生命周期标注
大部分情况下,rust 编译器可以通过 代码推出 引用的生命周期,比如上述例子,但是有些情况确无法推断出
先来一个简单的:
#[derive(Debug)]
struct Class {
id:i32,
num:i32,
}
#[derive(Debug)]
struct Student<'a> {
class: &'a Class,
}
fn main() {
let student_a: Student;
{
let class1:Class = Class {id:1, num:0};
student_a = Student{class: &class1};
}
println!("{:?}", student_a)
}
这个例子演示了,如果某个类型包含外部的引用, 必须要明确给出 生命周期占位符,因为该引用可能来自于不同的生命周期
当结构体通过使用<'a> 生命周期占位符以后,表示明确编译器,结构体变量的生命周期不能比<'a> 引用的生命周期长
换个方法说,引用的生命周期 <''a> 必须要比结构体实例的生命周期长
稍微复杂点的: 这也是C里面经常会遇到的情况,一个结构体包含另外一个结构体,但是另外一个结构体,也需要保存指向包含结构体的 对象指针
#[derive(Debug)]
struct Student<'a> {
name: String,
class_ref: &'a Class<'a>,
}
#[derive(Debug)]
struct Class<'a> {
id: i32,
students: Vec<Student<'a>>,
}
impl<'a> Class<'a> {
fn add_student(&'a mut self, name: &str) {
let students_ref = &mut self.students;
let nwe_stu = Student {
name: String::from(name),
class_ref: self,
};
students_ref.push(nwe_stu);
}
}
fn main() {
let mut class1 = Class {
id: 1,
students: Vec::new(),
};
class1.add_student("Jack");
class1.add_student("Rose");
}
这个问题,目前还没有办法解决,但是接下来的智能指针 或许能够给我们一些帮助