Neden birden fazla değiştirilebilir referans bir yapı üyesini kendisine atamayı imkansız kılıyor? [çiftleme]

Aug 17 2020

Yapabileceğimi düşündüğüm yerden ödünç alamıyorum. Sorunu şu duruma indirgedim:

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

Öyle görünüyor ki a.borrow, kesişme noktasına sahip 'bve 'cbu nedenle hala ömür boyu olacağı garanti edilemez 'c.

Bununla ilgili gerçek bir problemim yok ve her iki yaşamı da aynı yaparak bunun üstesinden gelebilirim, ama bu neden kontrol ödünç almıyor?


Görünüşe göre yapılar bu sorunu göstermek için önemsiz ve çift ödünç almalar bunu kolayca gösteriyor.

Oldukça benzer olan üç fonksiyonum var, ancak hangisinin derlendiğini ve derlenmeyenlerin hangi hatayı vereceğini bilmekte zorlanırım.

Basit genel işlev:

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

hataya neden olur:

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

Ekstra bir yönlendirme seviyesi dahil etmek hatayı değiştirir

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

Belirtilen yaşam sürelerinden farklı bir yere gitmek hatayı düzeltebilir:

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

Yanıtlar

Emoun Aug 18 2020 at 09:59

Yaşam sürelerinize bir göz atmanız gerekecek 'bve 'c:

  • &'b mut ...canlı ve bir "süre" için geçerli bir referansınız olduğu anlamına gelir 'b.
  • A<'c>canlı ve geçerli bir nesneye sahip olduğunuz anlamına gelir 'c.

Sahip olmadığınız şey, bu iki yaşam arasındaki belirli bir ilişkidir. Derleyicinin çıkarabileceği tek şey, a'nın A<'c>arkasında olduğu için &'b, 'cdaha uzun ömürlü olması 'b, yani ne zaman 'bgeçerli olursa olsun öyle olmasıdır 'c. Yine de, en önemlisi, tam tersi değil.

Göstermek gibi, derleyici gerektirir 'bve 'caynı ömrün nasıl. Bu neden?

İmkanlarımıza bir göz atalım:

  1. 'cve 'bhiçbir ilişkisi yoktur: Herhangi bir ilişki olmadan derleyicinin neyin konulacağı hakkında hiçbir şey garanti edemeyeceğini A.borrowve bu nedenle buna izin vermeyeceğini görmek kolaydır .
  2. 'ckesinlikle outlives 'bbazı yerlerde, yani 'cgeçerlidir 'bdeğildir:
    a.borrow = a.borrowbir reborrow olur akullanarak 'bömrünü. Bu cevap bunun neden olduğunu açıklıyor . Bununla birlikte, bu aartık 'byaşam süresine bağlı olduğu anlamına gelir, bu da bir süre aiçin geçerli değildir (çünkü ayaşam süresi de vardır 'c). Bu hatayı verir.
  3. 'bkesinlikle uzun ömürlüdür 'c: Bu ilişkimiz olsaydı, işe yarayabilirdi. Yeniden ödünç alma geçerli olacaktır, çünkü istediğimizden ( 'b) "daha büyük" bir ömür ( ) elde ederiz 'c. Bununla birlikte, 'c: 'bderleyici tarafından perde arkasından zaten çıkardık. Bu nedenle, bu yaşamı eklemek, iki yaşamın eşit olduğu ve o zaman başladığımız yere geri döndüğümüz anlamına gelir:
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;
}