首页 > 解决方案 > 为什么编译器错误会抱怨多个可变引用而不是悬空引用?

问题描述

我试图了解当函数重新借用可变引用时究竟会发生什么。

fn main() {
    let mut a = String::new();
    let mut b = String::new();
    let aa = &mut a;
    let c = my_fun(aa, &mut b);
    let d = &mut a;
    println!("{}", c);
}
                
fn my_fun<'b>(x: &'b mut String, y: &'b mut String) -> &'b mut String { y }

据我了解,my_fun 重新借用aa&*aa范围将是my_fun. 但是由于我在函数签名中创建的生命周期限制,重借应该至少与&mut b存在一样长。所以println强制reborrow活到它为止。

这不应该在 free 之后抛出使用错误,因为匿名重借只有内部范围my_fun吗?在这个函数之外,这个引用应该是无效的。

但我得到的错误是:

error[E0499]: cannot borrow `a` as mutable more than once at a time
 --> src/main.rs:7:13
  |
5 |     let aa= &mut a;
  |             ------ first mutable borrow occurs here
6 |     let c = my_fun(aa, &mut b);
7 |     let d = &mut a;
  |             ^^^^^^ second mutable borrow occurs here
8 |     println!("{}", c);
  |                    - first borrow later used 

如果可变引用只是被复制而不是在函数内部重新借用,这将是有意义的。

标签: rustborrow-checker

解决方案


据我了解,my_fun重新借用aa&*aa范围将是my_fun.

不完全是这样。

让我们回溯一下:为什么要再借?

&T和之间有一个根本的区别&mut T&TCopy,而&mut T不是偶数Clone。结果是&mut T只能移动,因此调用如下:

let x: &mut T = /*...*/;
func(x);

会导致x调用后无法使用。解决方法是引入一个临时的:

let x: &mut T = /*...*/;
let tmp = &mut *x;
func(tmp);

这个临时将重新借用 的指针x,并被 消耗func

而且……那是再借!编译器内置了这个“临时”创建,纯粹是为了符合人体工程学!

考虑到这一点,让我们回到:

据我了解,my_fun重新借用aa&*aa范围将是my_fun.

生命周期通常是一个范围而不是一个,这在这里是正确的。

tmp在我上面的例子中,生命周期受到两种方式的限制:

  • 它不能大于x
  • 不能小于func

这是另一种说法,它可以是这些界限之间的任何东西


推荐阅读