首页 > 解决方案 > 当返回对作用域外值的可变引用的不可变引用时,为什么在作用域结束时会丢弃可变引用?

问题描述

fn main() {
    // block1: fails
    {
        let mut m = 10;

        let n = {
            let b = &&mut m;
            &**b // just returning b fails
        };

        println!("{:?}", n);
    }

    // block2: passes
    {
        let mut m = 10;

        let n = {
            let b = &&m;
            &**b // just returning b fails here too
        };

        println!("{:?}", n);
    }
}

block1失败并出现以下错误:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:7:22
   |
7  |             let b = &&mut m;
   |                      ^^^^^^ temporary value does not live long enough
8  |             &**b // just returning b fails
9  |         };
   |         - temporary value dropped here while still borrowed
...
12 |     }
   |     - temporary value needs to live until here

我是否正确假设内部不可变引用超出了block2范围,而在block1中,即使有外部引用,内部可变引用也总是被删除?

标签: rustmutabledereferenceborrowing

解决方案


在这里将可变借用视为非Copy结构(S在下面的片段中)就足够了,它拥有引用值的所有权。该模型代表了可变借用的排他性。

基于此模型的推理:在 block2n中是对 original 的引用m,而在 block1中最终将是对可变借用所拥有n的副本的引用。m在这两个块中,内部引用在 let-block 的末尾被删除,但只有在 block1 中这会导致问题,因为在 block1 中,n当这个内部引用被删除时,引用的目标仍然由内部引用拥有。

struct S { m: i32 }
let mut m = 10;

let n = {
    let s = S { m };
    let b = &s;
    &(*b).m
}; // s is dropped

println!("{:?}", n);

在上面的代码片段s中,拥有m. 引用n将指向n删除时s删除的副本 - 不允许。如果m是非复制,m则将移至s,这将具有相同的含义。

在 block2 中,m直接借用原件而不复制它。如果你强制复制,你会得到与 block1 相同的错误:

let mut m = 10;

let n = {
    let m2 = m;
    let mut a = &m2;
    let b = &a;
    &**b
};

println!("{:?}", n);

推荐阅读