文章目录

生命周期(lifetime) 是这样一种概念,编译器(中的借用检查器)用它来保证所有的借用都是有效的。确切地说,一个变量的生命周期在它创建的时候开始,在它销毁的时候结束。

例如考虑这种情况,我们通过​​&​​来借用一个变量。该借用拥有一个生命周期,此生命周期由它声明的位置决定。于是,只要该借用在出借者(lender)被销毁前结束,借用就是有效的。然而,借用的作用域则是由使用引用的位置决定的。

一、函数

排除​​省略(elision)​​的情况,带上生命周期的函数签名有一些限制:

  • 任何引用都必须拥有标注好的生命周期。
  • 任何被返回的引用都必须有和某个输入量相同的生命周期或是静态类型( static )。

另外要注意,如果没有输入的函数禁止返回引用,有时会导致返回的引用指向无效数据。

下面例子展示了一些合法的带有生命周期的函数:

//一个拥有生命周期`'a`的输入引用,其中`'a`的存活时间至少与函数的一样长。
// 说白话就是('a的生命>=函数的生命)
fn print_one<'a>(x: &'a i32) {
println!("`print_one`: x is {}", x);
}

//可变引用同样也可能拥有生命周期。
fn add_one<'a>(x: &'a mut i32) {
*x += 1;
}

fn print_multi<'a, 'b>(x: &'a i32, y: &'b i32) {
println!("`print_multi`: x is {}, y is {}", x, y);
}


fn pass_x<'a, 'b>(x: &'a i32, _: &'b i32) -> &'a i32 { x }


fn main() {
let x = 7;
let y = 9;

print_one(&x);
print_multi(&x, &y);

let z = pass_x(&x, &y);
print_one(z);

let mut t = 3;
add_one(&mut t);
print_one(&t);
}

// `print_one`: x is 7
// `print_multi`: x is 7, y is 9
// `print_one`: x is 7
// `print_one`: x is 4

二、方法

struct Owner(i32,i32);

impl Owner {
fn add_one<'a>(&'a mut self) {self.0 +=1; self.1+=2}
fn print<'a>(&'a mut self) {
println!("println is {};{}",self.0,self.1);
}
}

fn main() {
let mut owner = Owner(12,24);

owner.add_one();
owner.print();
}

//println is 13;26

三、结构体 枚举体

结构体或枚举体引用的元素比结构体或枚举体寿命更长,使用方法同上,并没有什么特别的。

#[derive(Debug)]
struct People<'a>{
age:&'a i32,
height:&'a i32,
}

impl <'a>Default for People<'a>{
fn default() -> Self {
Self {
age:&0,
height:&0,
}
}
}

#[derive(Debug)]
enum Color<'a>{
Red(&'a u8),
Green(&'a u8),
Blue(u8),
}

fn main() {
let x_0 = 11;
let y_0 = 130;

let a = 125u8;
let b = 123u8;
let c = 77u8;

let single = People{age:&x_0,height:&y_0};
let single_default = People::default();
let zhangsan = Color::Red(&a);
let lisi = Color::Green(&b);
let wangwu = Color::Blue(c);

println!("single is borrowed in {:?}",single);
println!("single_default is borrowed in {:?}",single_default);
println!("zhangsan is borrowed in {:?}=={:?}=={:?}",zhangsan,lisi,wangwu);
}

// single is borrowed in People { age: 11, height: 130 }
// single_default is borrowed in People { age: 0, height: 0 }
// zhangsan is borrowed in Red(125)==Green(123)==Blue(77)

四、trait 约束

trait 方法中生命期的标注基本上与函数类似。
就如泛型类型能够被约束一样,生命周期(它们本身就是泛型)也可以使用约束。 ​​​:​​​字符的意义在这里稍微有些不同,不过 ​​+​​ 是相同的。

  1. ​T:'a​​​ :在​​T​​​中的所有引用都必须比生命周期​​'a​​活得更长。
  2. ​T:Trait+'a​​​:​​T​​​类型必须实现​​Trait​​​ trait,并且在​​T​​​中的所有引用都必须比​​'a​​活得更长。
use std::fmt::Debug;

#[derive(Debug)]
struct Ref<'a,T:'a>(&'a T);
//Ref包含一个指向泛型类型T的引用,其中T拥有一个未知的生命周期'a。
//T中的任何*引用*都必须比'a活得更长。另外Ref的生命周期也不能超出'a。

fn print<T>(t:T) where
T:Debug{
println!("println:t is {:?}",t);
}

fn print_ref<'a,T>(t:&'a T)where
T:Debug{
println!("println_ref:t is {:?}",t);
}


fn main() {
let x = 7;
let ref_x = Ref(&x);

print_ref(&ref_x);
print(ref_x);
}

// println_ref:t is Ref(7)
// println:t is Ref(7)

多参数引用与强制转换
如下示例:生命周期​​​'a​​​至少和​​'b​​​一样长。 ​​lifetime:'a>='b​

fn multiply<'a>(first:&'a i32, second:&'a i32)->i32 {
first * second
}

fn choose_first<'a:'b,'b>(first:&'a i32, _:&'b i32)->&'b i32 {
first
}


fn main() {
let first = 3;
{
let second = 4;
println!("Multiple first*second = {}",multiply(&first,&second));
println!("The first is = {}",choose_first(&first,&second));
}
}

// Multiple first*second = 12
// The first is = 3