複数の可変参照により、構造体のメンバーをそれ自体に割り当てることができないのはなぜですか?[複製]

Aug 17 2020

思ったところに借りられない。私はこの場合に問題を減らしました:

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

私はこれに実際の問題はなく、両方のライフタイムを同じにすることで回避できますが、なぜこれがチェックを借用しないのですか?


構造体はこの問題を示すのに重要ではないようで、二重借用はそれを簡単に示します。

私には非常によく似た3つの関数がありますが、どれがコンパイルされ、どのエラーがコンパイルされないのかを知るのに苦労します。

単純なジェネリック関数:

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;
}

回答

Emoun Aug 18 2020 at 09:59

あなたはあなたの生涯'bを見てみる必要があります'c

  • &'b mut ...ライブで「時間」有効な参照があることを意味します'b
  • A<'c>ライブで有効なオブジェクトがあることを意味します'c

あなたが持っていないのは、これらの2つの生涯の間の特定の関係です。コンパイラが推測できる唯一のことは、A<'c>がの背後にあるため&'b'c長生きする必要があるということです。'bつまり、'b有効なときはいつでも、です'c。ただし、決定的には、その逆ではありません。

あなたが示すように、コンパイラは同じ寿命である必要が'bあり'cます。どうしてこれなの?

私たちの可能性を見てみましょう:

  1. 'cそして、'b関係ありません:それはどんな関係なしにそれを簡単に確認することができ、コンパイラは入れているかについてではない保証は何もすることができA.borrow、そのようにはそれを許可しません。
  2. 'c厳密に長生きします'b。つまり、一部の場所'cは有効で'bはありません。生涯
    a.borrow = a.borrowa使用することの再借用になり'bます。この答えは、なぜそれが起こるのかを説明しています。しかし、この手段a今に依存している'b時間の一部が無効です寿命、a(以降有効なa寿命を持っています'c)。これによりエラーが発生します。
  3. 'b厳密に長生きする'c:この関係があれば、うまくいくかもしれません。'b要求した('c)よりも「長い」ライフタイム()が得られるため、再借用は有効になります。ただし、'c: 'bコンパイラは舞台裏ですでに推測しています。したがって、このライフタイムを追加すると、2つのライフタイムが等しくなり、開始した場所に戻ります。
struct A<'a> {
    borrow: &'a mut u8,
}

/// We add the relation 'b: 'c
fn does_nothing<'b: 'c, 'c>(a: &'b mut A<'c>) {
    a.borrow = a.borrow;
}