ใน Rust ฉันจะสร้างตัววนซ้ำที่เปลี่ยนแปลงได้อย่างไร [ซ้ำ]

Aug 16 2020

ฉันมีปัญหากับชีวิตเมื่อพยายามสร้างตัววนซ้ำที่ไม่แน่นอนใน Safe Rust

นี่คือสิ่งที่ฉันลดปัญหาของฉันเป็น:

struct DataStruct<T> {
    inner: Box<[T]>,
}

pub struct IterMut<'a, T> {
    obj: &'a mut DataStruct<T>,
    cursor: usize,
}

impl<T> DataStruct<T> {
    fn iter_mut(&mut self) -> IterMut<T> {
        IterMut { obj: self, cursor: 0 }
    }
}

impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        let i = f(self.cursor);
        self.cursor += 1;
        self.obj.inner.get_mut(i)
    }
}

fn f(i: usize) -> usize {
   // some permutation of i
}

โครงสร้างของDataStructเจตจำนงของฉันจะไม่เปลี่ยนแปลง แต่ฉันต้องสามารถกลายพันธุ์เนื้อหาขององค์ประกอบที่เก็บไว้ภายใน ตัวอย่างเช่น,

let mut ds = DataStruct{ inner: vec![1,2,3].into_boxed_slice() };
for x in ds {
  *x += 1;
}

คอมไพเลอร์แจ้งข้อผิดพลาดเกี่ยวกับอายุการใช้งานที่ขัดแย้งกันสำหรับข้อมูลอ้างอิงที่ฉันพยายามส่งคืน อายุการใช้งานพบว่าฉันไม่คาดคิดคือขอบเขตของnext(&mut self)ฟังก์ชัน

ถ้าฉันพยายามใส่คำอธิบายประกอบตลอดอายุการใช้งานnext()คอมไพเลอร์จะบอกฉันว่าฉันไม่พอใจกับลักษณะ Iterator แทน สามารถแก้ไขได้ในสนิมปลอดภัยหรือไม่?

นี่คือข้อผิดพลาด:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
  --> src/iter_mut.rs:25:24
   |
25 |         self.obj.inner.get_mut(i)
   |                        ^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 22:5...
  --> src/iter_mut.rs:22:5
   |
22 | /     fn next(&mut self) -> Option<Self::Item> {
23 | |         let i = self.cursor;
24 | |         self.cursor += 1;
25 | |         self.obj.inner.get_mut(i)
26 | |     }
   | |_____^
note: ...so that reference does not outlive borrowed content
  --> src/iter_mut.rs:25:9
   |
25 |         self.obj.inner.get_mut(i)
   |         ^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 19:6...
  --> src/iter_mut.rs:19:6
   |
19 | impl<'a, T> Iterator for IterMut<'a, T> {
   |      ^^
note: ...so that the types are compatible
  --> src/iter_mut.rs:22:46
   |
22 |       fn next(&mut self) -> Option<Self::Item> {
   |  ______________________________________________^
23 | |         let i = self.cursor;
24 | |         self.cursor += 1;
25 | |         self.obj.inner.get_mut(i)
26 | |     }
   | |_____^
   = note: expected  `std::iter::Iterator`
              found  `std::iter::Iterator`

แก้ไข :

  • เปลี่ยนการนำไปใช้next()เพื่อให้ลำดับการวนซ้ำเป็นการเปลี่ยนแปลงลำดับเดิม

คำตอบ

3 PeterHall Aug 16 2020 at 15:06

เครื่องตรวจสอบการยืมไม่สามารถพิสูจน์ได้ว่าการโทรครั้งต่อ ๆ ไปnext()จะไม่เข้าถึงข้อมูลเดียวกัน สาเหตุที่เป็นปัญหาเนื่องจากอายุการใช้งานของการยืมนั้นเป็นไปตามช่วงอายุของตัววนซ้ำดังนั้นจึงไม่สามารถพิสูจน์ได้ว่าจะไม่มีการอ้างอิงข้อมูลเดียวกันสองรายการในเวลาเดียวกันที่ไม่แน่นอน

ไม่มีวิธีใดที่จะแก้ปัญหานี้ได้หากไม่มีรหัสที่ไม่ปลอดภัยหรือเปลี่ยนโครงสร้างข้อมูลของคุณ คุณสามารถทำ equlivant ได้slice::split_at_mutแต่เนื่องจากคุณไม่สามารถกลายพันธุ์ข้อมูลเดิมได้คุณจะต้องใช้สิ่งนั้นในโค้ดที่ไม่ปลอดภัยอยู่ดี การติดตั้งที่ไม่ปลอดภัยอาจมีลักษณะดังนี้:

impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        let i = self.cursor;
        self.cursor += 1;
        if i < self.obj.inner.len() {
            let ptr = self.obj.inner.as_mut_ptr();
            unsafe {
                Some(&mut *ptr.add(i))
            }
        } else {
            None
        }
    }
}