为什么多个可变引用使无法将结构的成员分配给自身?

问题描述

我无法在我认为可以的地方借钱。我将问题归结为这种情况:

struct A<'a> {
    borrow: &'a mut u8,}

fn does_nothing<'b,'c>(a: &'b mut A<'c>) {
    a.borrow = a.borrow;
}
error[E0623]: lifetime mismatch
 --> src/lib.rs:6:16
  |
5 | fn does_nothing<'b,'c>(a: &'b mut A<'c>) {
  |                            -------------
  |                            |
  |                            these two types are declared with different lifetimes...
6 |     a.borrow = a.borrow;
  |                ^^^^^^^^ ...but data from `a` flows into `a` here

似乎a.borrow具有'b'c的交集,因此不能保证仍然具有生存期'c

我对此没有任何实际问题,可以通过使两个生命周期相同来解决此问题,但是为什么这不借用检查呢?


似乎结构对于显示此问题并不重要,而双重借用则易于显示

我有三个函数,它们非常相似,但是我很难知道哪个函数可以编译,而非编译函数会给出哪些错误

简单的通用函数

fn only_borrow<T>(a: &mut T) {
    *a = *a;
}

导致错误

error[E0507]: cannot move out of `*a` which is behind a mutable reference
 --> src/lib.rs:2:10
  |
2 |     *a = *a;
  |          ^^ move occurs because `*a` has type `T`,which does not implement the `copy` trait

包含额外的间接级别会更改错误

fn only_borrow_double<T>(a: &mut &mut T) {
    *a = *a;
}
error[E0623]: lifetime mismatch
 --> src/lib.rs:2:10
  |
1 | fn only_borrow_double<T>(a: &mut &mut T) {
  |                             -----------
  |                             |
  |                             these two types are declared with different lifetimes...
2 |     *a = *a;
  |          ^^ ...but data from `a` flows into `a` here

远离隐含的寿命可以修复错误

fn working_double<'b,T>(a: &'b mut &'b mut T) {
    *a = *a;
}

解决方法

您必须查看自己的一生'b'c

  • &'b mut ...意味着您拥有一个在“时间” 'b内有效且有效的参考。
  • A<'c>表示您拥有一个对'c有效且有效的对象。

您没有的是这两个生命周期之间的特定关系。编译器唯一可以推断的是,由于A<'c>位于&'b的后面,因此'c的生存期必须长于'b,也就是说,只要'b有效,那么{ 'c。不过,至关重要的是,并非相反。

如您所示,编译器要求'b'c具有相同的生存期。 为什么会这样?

让我们看看我们的可能性:

  1. 'c'b没有关系:很容易看出,没有任何关系,编译器无法保证有关A.borrow中内容的任何保证,因此不允许它。
  2. 'c严格超过'b,也就是说,某些地方'c有效'b不是:
    a.borrow = a.borrow的生存期内,a成为'b的借入。 This answer explains why that happens。但是,这意味着a现在取决于'b的生存期,在a有效的某些时间内无效(因为a的生存期为{{ 1}})。这给出了错误。
  3. 'c的生存期完全超过'b:如果我们有这种关系,它可能会起作用。重新借贷将是有效的,因为我们的生存期('c)比我们要求的('b)更长。但是,编译器已经在幕后推断出'c。因此,添加此生存期意味着两个生存期变得相等,然后我们回到起点:
'c: 'b