调用 return 引用的函数时了解非词法生命周期

Understanding non lexical lifetimes when calling functions that return reference

以下函数对于 NLL

工作正常
fn main() {
    let mut x = 1i32;
    let mut y = &mut x;

    let z = &mut y; 

    *y = 12;
}

但是,如果我用函数调用(基本上做同样的事情)替换语句 let z = &mut y,借用检查器会抱怨。

fn test<'a>(x:&'a mut &'a mut i32) -> &'a mut i32 {
    &mut **x
}

fn main() {
    let mut x = 1i32;
    let mut y = &mut x;

    let z = test(&mut y);

    *y = 12;
}

给出以下错误:

error[E0506]: cannot assign to `*y` because it is borrowed
  --> src/main.rs:11:5
   |
9  |     let z = test(&mut y);
   |                  ------ borrow of `*y` occurs here
10 |     
11 |     *y = 12;
   |     ^^^^^^^
   |     |
   |     assignment to borrowed `*y` occurs here
   |     borrow later used here

函数test()返回的引用已经不用了,难道不应该考虑'dead'吗?

让我们为程序中的生命周期命名。 (这不会编译,但用于演示目的。)

在您的第一个示例中,我们有两个生命周期,'1'2。生命周期 '2 只持续一行,所以 y 可以在以后使用:

fn main() {
    let mut x = 1i32;      //
    let mut y = &'1 mut x; //        ^
                           //        |
    let z = &'2 mut y;     //  |'2   |'1
                           //        |
    *y = 12;               //        v
}

在第二个示例中,因为 test 需要 &'a mut &'a mut i32,其中 'a 表示相同的生命周期,外部引用必须与内部引用一样长。这就是我们收到错误的原因:

fn test<'a>(x:&'a mut &'a mut i32) -> &'a mut i32 {
    &mut **x
}

fn main() {
    let mut x = 1i32;        //
    let mut y = &'1 mut x;   //        ^
                             //        |
    let z = test(&'2 mut y); //  |'2   |'1
                             //  |     |
    *y = 12;                 //  v     v
}

但是,如果我们给 test 两个不同的生命周期,代码现在可以正常编译,因为我们回到了与第一个示例相同的情况:

fn test<'a, 'b>(x:&'a mut &'b mut i32) -> &'a mut i32 {
    &mut **x
}

fn main() {
    let mut x = 1i32;        //
    let mut y = &'1 mut x;   //        ^
                             //        |
    let z = test(&'2 mut y); //  |'2   |'1
                             //        |
    *y = 12;                 //        v
}