เหตุใดการอ้างอิงที่เปลี่ยนแปลงได้หลายรายการจึงทำให้ไม่สามารถกำหนดสมาชิกของโครงสร้างให้กับตัวเองได้ [ซ้ำ]

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

ฉันไม่มีปัญหาจริงๆกับสิ่งนี้และสามารถแก้ไขได้โดยทำให้อายุการใช้งานทั้งสองเหมือนกัน แต่ทำไมถึงไม่ยืมเช็ค?


ดูเหมือนว่าโครงสร้างจะไม่สำคัญต่อการแสดงปัญหานี้และการยืมสองครั้งก็แสดงให้เห็นได้อย่างง่ายดาย

ฉันมีสามฟังก์ชั่นที่คล้ายกันมาก แต่ฉันจะมีปัญหาในการรู้ว่าอันไหนคอมไพล์และข้อผิดพลาดใดที่ฟังก์ชันที่ไม่ได้รวบรวมจะให้

ฟังก์ชันทั่วไปที่เรียบง่าย:

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หมายความว่าคุณมีวัตถุที่เป็นที่อยู่อาศัยและที่ถูกต้องสำหรับ

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