生命周期

  • Rust 中的每一个引用都有其生命周期:引用有效的作用域。
  • 大部分情况下生命周期都是隐式和自举的,在无法完成的情况下就需要我们通过生命周期泛型参数帮助编译器进行注解。
  • 生命周期的主要目标是避免悬空指针。
  • 生命周期泛型参数定义各个引用之间(参数和参数、参数和返回值)的关系,并不改变(延长)变量原本的生命周期
&i32        // a reference
&'a i32     // a reference with an explicit lifetime
&'a mut i32 // a mutable reference with an explicit lifetime

参考以下代码

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
		if x.len() > y.len() {
				x
		} else {
				y
		}
}

以上代码

  • 标注生命周期 'a
  • 函数有两个引用参数,都使用生命周期 'a 表示两个参数的生命周期必须一致(存活的周期一样长)
  • 函数返回一个引用,并且存活的时间和生命周期 'a 一致
  • 以上指定不改变任何传入的引用的生命周期,我们只是要求借用检查器(borrow checker)检查这些约束。
  • 也就是说借用检查器要检查传入的两个引用的生命周期必须一致,返回的引用的存活周期不能超过传入的引用的存活周期

思考

当函数返回一个引用时,返回值的生命周期注解要和参数的其中之一相匹配,否则那么引用就是指向里函数内创建的值(不能返回)。 也就是说返回引用时,引用的声明周期必须和参数(其一)相关。如果想要返回函数内创建的值最好返回一个有所有权的值类型。

结构体生命周期

如果结构体需要持有引用,需要在定义结构体时给每一个引用都加上生命周期注解。

如果结构体声明了生命周期参数,那么 impl 同样也要声明。

struct ImportantExcerpt<'a> {
		part: &'a str,
}

impl<'a> ImportantExcerpt<'a> {
		fn announce_and_return_part(&self, announcement: &str) -> &str {
				println!("Attention please: {}", announcement);
				self.part
		}
}

生命周期省略(elision)规则

  • 函数参数的生命周期为输入生命周期
  • 函数返回值的生命周期为输出生命周期

3 个规则用于 fnimpl

  • 函数的每个引用参数都有一个生命周期: fn foo<'a, 'b>(x: &'a i32, y: &'b i32)
  • 如果只有一个引用参数,那么将输入的生命周期注解将应用到所有输出上
  • 如果有多个参数,但包含一个 &self&mut self 那么 self 的生命周期将分配到所有输出参数上。

扩展文章