Mengapa beberapa referensi yang bisa berubah membuat tidak mungkin untuk menetapkan anggota struct untuk dirinya sendiri? [duplikat]
Saya tidak dapat meminjam di mana saya pikir saya bisa. Saya mengurangi masalah menjadi kasus ini:
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
Tampaknya a.borrow
memiliki persimpangan 'b
dan 'c
dan karena itu tidak dapat dijamin masih memiliki seumur hidup 'c
.
Saya tidak memiliki masalah nyata dengan ini dan dapat mengatasinya dengan membuat kedua masa hidup sama, tetapi mengapa ini tidak meminjam cek?
Tampaknya struct tidak penting untuk menunjukkan masalah ini dan pinjaman ganda menunjukkannya dengan mudah.
Saya memiliki tiga fungsi yang sangat mirip, tetapi saya akan kesulitan mengetahui mana yang dapat dikompilasi dan kesalahan mana yang akan diberikan oleh yang tidak dikompilasi.
Fungsi umum sederhana:
fn only_borrow<T>(a: &mut T) {
*a = *a;
}
menghasilkan kesalahan:
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
Memasukkan tingkat tipuan ekstra mengubah kesalahan
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
Mengubah masa pakai yang tersirat dapat memperbaiki kesalahan:
fn working_double<'b, T>(a: &'b mut &'b mut T) {
*a = *a;
}
Jawaban
Anda harus melihat masa hidup Anda 'b
dan 'c
:
&'b mut ...
berarti Anda memiliki referensi yang aktif dan valid untuk suatu "waktu"'b
.A<'c>
berarti Anda memiliki objek yang hidup dan valid'c
.
Apa yang tidak Anda miliki adalah hubungan khusus antara dua masa kehidupan ini. Satu-satunya hal yang dapat disimpulkan oleh kompilator adalah karena A<'c>
berada di belakang a &'b
, 'c
must outlive 'b
, yaitu, kapan pun 'b
valid, begitu juga 'c
. Padahal, yang terpenting, bukan sebaliknya.
Seperti yang Anda tunjukkan, kompilator membutuhkan 'b
dan 'c
seumur hidup yang sama. Kenapa ini?
Mari kita lihat kemungkinan kita:
'c
dan'b
tidak memiliki hubungan: Sangat mudah untuk melihat bahwa tanpa hubungan apapun, kompilator tidak dapat menjamin apapun tentang apa yang dimasukkanA.borrow
dan dengan demikian tidak akan mengizinkannya.'c
benar-benar hidup lebih lama'b
, yaitu, beberapa tempat'c
valid'b
tidak:
a.borrow = a.borrow
menjadi peminjaman kembalia
menggunakan'b
seumur hidup. Jawaban ini menjelaskan mengapa hal itu terjadi . Namun, ini berarti bahwaa
sekarang tergantung pada masa'b
hidup, yang tidak berlaku untuk beberapa waktua
yang sah (karenaa
memiliki masa hidup'c
). Ini memberikan kesalahan.'b
benar-benar hidup lebih lama'c
: Jika kita memiliki hubungan ini, itu mungkin berhasil. Peminjaman kembali akan valid, karena kita mendapatkan masa hidup yang "lebih besar" ('b
) daripada yang kita minta ('c
). Namun, kami telah'c: 'b
menyimpulkan oleh kompilator di balik layar. Oleh karena itu, menambahkan masa hidup ini berarti kedua masa kehidupan menjadi sama dan kita kemudian kembali ke tempat kita memulai:
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;
}