Rust生命周期详细图解

本文概述

  • 生存期定义了引用有效的范围。
  • 生命周期是隐式和推断的。
  • Rust使用通用生命周期参数来确保使用有效的实际引用。

防止使用生命周期悬挂参考

程序尝试访问无效引用时, 称为”悬空引用”。指向无效资源的指针称为”悬空指针”。

让我们看一个简单的例子:

fn main()
{
  let a;
  {
    let b = 10;
     a = &b;
  }
  println!("a : {}", a);
}

输出

Rust生命周期详细图解

在上面的示例中, 外部范围包含名为” a”的变量, 并且不包含任何值。内部作用域包含变量” b”, 并存储值10。变量” b”的引用存储在变量” a”中。当内部作用域结束时, 我们尝试访问” a”的值。 Rust编译器将抛出编译错误, 因为” a”变量是指超出范围的变量的位置。 Rust将使用借用检查器确定代码无效。

借阅检查器

借用检查器用于解决悬挂引用的问题。借用检查器用于比较范围以确定它们是否有效。

Rust生命周期详细图解

在上面的示例中, 我们用’a注释了’a’变量的生存期, 并用’b注释了’b’变量的生存期。在编译时, Rust将拒绝此程序, 因为’a’变量的生存期大于’b’变量的生存期。上面的代码可以修复, 这样就不会发生编译器错误。

Rust生命周期详细图解

在上面的示例中, ” a”变量的生存期短于” b”变量的生存期。因此, 以上代码运行没有任何编译错误。

终身注释语法

  • 终身注释不会更改任何引用的生存时间。
  • 函数也可以使用通用生命周期参数接受任何生命周期的引用。
  • 生命周期注释描述了多个参数的生命周期之间的关系。

生命周期注释语法应遵循的步骤:

  • 生存期参数的名称应以(‘)撇号开头。
  • 它们主要是小写和简短的。例如:
  • 将生命周期参数注释放置在引用的”&”之后, 然后用空格将注释与引用类型分开。

生命周期注释语法的一些示例如下:

  • &i32 //参考
  • &’a i32 //具有给定寿命的引用。
  • &’mut i32 //具有给定生存期的可变引用。

功能签名中的终身注释

‘a表示参考的有效期。每个参考都有与之关联的生命周期。我们也可以在函数签名中使用生命周期注释。通用生命周期参数在尖括号<>之间使用, 并且尖括号放在函数名称和参数列表之间。我们看看吧:

fn fun<'a>(...);

在上述情况下, fun是具有一个生存期的函数名称, 即’a。如果一个函数包含两个具有两个不同生存期的参考参数, 则可以将其表示为:

fn fun<'a, 'b>(...);

如果一个函数包含一个名为” y”的变量。

如果” y”是不可变的引用, 则参数列表将为:

fn fun<'a>(y : & 'a i32);

如果” y”是可变引用, 则参数列表为:

fn fun<'a>(y : & 'a mut i32);

&’a i32和&’a mut i32都是相似的。唯一的区别是’a位于&和mut之间。

&mut i32表示”对i32的可变引用”。

&’mut i32的意思是”对生存期为’a的i32的可变引用”。

生命周期注释

我们也可以像在函数中使用的那样在结构体中使用显式生存期。

我们看看吧:

struct Example
      {
          x : & 'a i32, //  x is a variable of type i32 that has the lifetime 'a.
      }

让我们看一个简单的例子:

struct Example<'a> {
    x: &'a i32, }
fn main() {
    let y = &9; 
    let b = Example{ x: y };
    println!("{}", b.x);
}

输出

9

展示块

我们可以使用impl块实现具有生命周期’a的结构类型。

让我们看一个简单的例子:

struct Example<'a> {
    x: &'a i32, }
impl<'a> Example<'a>
{
fn display(&self)
{
  print!("Value of x is : {}", self.x);
}
}
fn main() {
    let y = &90; 
    let b = Example{ x: y };
    b.display();
}

输出

Value of x is : 90

多个生存期

我们可以有两种可能性:

  • 多个引用具有相同的生存期。
  • 多个引用具有不同的生存期。

当引用具有相同的生存期时。

fn fun <'a>(x: & 'a i32 , y: & 'a i32) -> & 'a i32
{
    //block of code.
}

在上述情况下, 参考x和y的寿命相同, 即’a。

当引用具有不同的生存期时。

fn fun<'a , 'b>(x: & 'a i32 , y: & 'b i32) 
{
    // block of code.
}

在上述情况下, 参考x和y都有不同的寿命, 即分别为’a和’b。

‘静态的

称为”静态”的生存期是特殊的生存期。它表示具有生命周期”静态”的对象将具有整个程序的生命周期。弦的使用寿命主要是”静态寿命”。具有”静态寿命”的引用对整个程序均有效。

我们看看吧:

let s : & 'static str = "srcmini tutorial" ;

Lifetime Ellision

Lifetime Ellision是一种推理算法, 可使常见模式更符合人体工程学。 Lifetime Ellision使程序变得笨拙。

Lifetime Ellision可以在以下任何地方使用:

  • & ‘在
  • 和mut T
  • T <‘a>

终生疾病可以两种方式出现:

  • 输入生命周期:输入生命周期是与函数参数关联的生命周期。
  • 输出生存期:输出生存期是与函数的返回类型关联的生存期。

我们看看吧:

fn fun<'a>( x : & 'a i32);                       // input lifetime
 fn fun<'a>() -> & 'a i32;                      // output lifetime
fn fun<'a>(x : & 'a i32)-> & 'a i32;      // Both input and output lifetime.

终身免除规则:

  • 引用传递的每个参数都有一个不同的生命周期注释。
fn fun(x:&i32, y:&i32) { }
fn fun <‘a, ‘b>(x:&’a i32, y:&’b i32) { }
  • 如果单个参数通过引用传递, 则该参数的生存期将分配给所有省略的输出生存期。
fn fun(x:i32, y:&i32)->&i32 { }
fn fun <‘a>(x:i32, y:&’a i32)->&’a i3 { }
  • 如果通过引用传递的多个参数(其中之一是&self或&mut self), 则将self的生存期分配给所有被忽略的输出生存期。
fn fun(&self, x:&str) { }
fn fun <‘a, ‘b>(&’a self, x:&’b str)->&’a str { }

例如:

fn fun(x:&str); //省略形式。

fn fun <‘a>(x:&’a str)->&’a str; //展开形式。


微信公众号
手机浏览(小程序)
0
分享到:
没有账号? 忘记密码?