เหตุใดการอ้างอิงที่เปลี่ยนแปลงได้หลายรายการจึงทำให้ไม่สามารถกำหนดสมาชิกของโครงสร้างให้กับตัวเองได้ [ซ้ำ]
ฉันไม่สามารถยืมที่ที่ฉันคิดว่าจะทำได้ ฉันลดปัญหาลงในกรณีนี้:
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
มีอายุการใช้งานเท่ากัน ทำไมถึงเป็นแบบนี้?
ให้เราดูความเป็นไปได้ของเรา:
'c
และ'b
ไม่มีความสัมพันธ์: เป็นเรื่องง่ายที่จะเห็นว่าไม่มีความสัมพันธ์ใด ๆ คอมไพเลอร์ไม่สามารถรับประกันอะไรเกี่ยวกับสิ่งที่ใส่เข้าไปได้A.borrow
และด้วยเหตุนี้จึงไม่อนุญาต'c
มีชีวิตอยู่อย่างเคร่งครัด'b
กล่าวคือสถานที่บางแห่ง'c
ไม่ถูกต้อง'b
:
a.borrow = a.borrow
กลายเป็นการa
ใช้'b
อายุการใช้งานซ้ำ คำตอบนี้อธิบายได้ว่าทำไมที่เกิดขึ้น อย่างไรก็ตามหมายความว่าa
ตอนนี้ขึ้นอยู่กับ'b
อายุการใช้งานซึ่งไม่ถูกต้องในบางช่วงเวลาa
นั้นใช้ได้ (เนื่องจากa
มีอายุการใช้งาน'c
) สิ่งนี้ทำให้เกิดข้อผิดพลาด'b
อายุยืนอย่างเคร่งครัด'c
: หากเรามีความสัมพันธ์นี้มันอาจใช้ได้ reborrow จะถูกต้องเนื่องจากเรามีอายุการใช้งานที่ "ใหญ่กว่า" ('b
) มากกว่าที่เราขอ ('c
) อย่างไรก็ตามเราได้'c: 'b
สรุปโดยคอมไพเลอร์เบื้องหลังแล้ว ดังนั้นการเพิ่มอายุการใช้งานนี้หมายความว่าอายุขัยทั้งสองจะเท่ากันและเราก็กลับมาที่จุดเริ่มต้น
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;
}