借用检查器

借用检查器将比较一个引用和一个有所有权的变量的生命周期

示例:x是所有权变量,生命周期是'br是引用,生命周期是'a
通过比较生命周期:当x无效时,r还拿着它的引用,因此不符合借用检查器的规则

  1. {
  2. let r; // ---------+-- 'a
  3. // |
  4. { // |
  5. let x = 5; // -+-- 'b |
  6. r = &x; // | |
  7. } // -+ |
  8. // |
  9. println!("r: {}", r); // |
  10. } // ---------+

函数生命周期注解

写法

声明的位置与泛型位置一致

  1. &i32 // 引用
  2. &'a i32 // 带有显式生命周期的引用
  3. &'a mut i32 // 带有显式生命周期的可变引用

为什么需要写注解

因为借用检查器需要判断返回值的生命周期是否小于所有权变量的生命周期
但是不确定返回值到底是使用了哪个参数的借用
所以需要标注一下生命周期参数,以下例说明,对于相同的注解'a:返回值的生命周期等同于xy的生命周期中较小的那一个。

示例:
生命周期较小的是y,因此借用检查器会把resultstring2进行比较,发现借用的所有权的生命周期还长,因此会报错:

  1. fn main() {
  2. let string1 = String::from("long string is long");
  3. let result;
  4. {
  5. let string2 = String::from("xyz");
  6. result = longest(string1.as_str(), string2.as_str());
  7. ^^^^^^^ borrowed value does not live long enough
  8. println!("The longest string is {}", result);
  9. }
  10. - `string2` dropped here while still borrowed
  11. println!("{}",result);
  12. ------ borrow later used here
  13. }
  14. fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
  15. if x.len() > y.len() {
  16. x
  17. } else {
  18. y
  19. }
  20. }

当从函数返回一个引用时,返回值的生命周期参数一定需要与其中一个参数的生命周期参数相匹配。如果返回的引用 没有 指向任何一个参数,那么唯一的可能就是它指向一个函数内部创建的值,它将会是一个悬垂引用,因为它将会在函数结束时离开作用域。

结构体的生命周期注解

结构体中的字段可能是一个引用,需要为其添加生命周期注解
这样,借用检查器就知道需要拿结构体实例的生命周期与其中字段引用的所有权变量的生命周期进行比较:

示例:结构体实例i,所有权变量是novel借用检查器会对它们的生命周期进行比较

  1. struct ImportantExcerpt<'a> {
  2. part: &'a str,
  3. }
  4. fn main() {
  5. let novel = String::from("Call me Ishmael. Some years ago...");
  6. let first_sentence = novel.split('.')
  7. .next()
  8. .expect("Could not find a '.'");
  9. let i = ImportantExcerpt { part: first_sentence };
  10. }

生命周期借用规则

规则1

每一个是引用的参数都有它自己的生命周期参数。

规则2

如果只有一个输入生命周期参数,那么它被赋予所有输出生命周期参数

规则3

如果方法有多个输入生命周期参数并且其中一个参数是&self&mut self,说明是个对象方法(method),那么所有输出生命周期参数被赋予self的生命周期

静态生命周期

'static,其生命周期能够存活于整个程序期间

所有的字符串字面值都拥有 'static 生命周期