Trong Rust, làm cách nào để tạo một trình lặp có thể thay đổi? [bản sao]
Tôi đang gặp khó khăn với các vòng đời khi cố gắng tạo một trình lặp có thể thay đổi trong Rust an toàn.
Đây là những gì tôi đã giảm vấn đề của mình thành:
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
}
Cấu trúc của ý chí của tôi DataStruct
không bao giờ thay đổi, nhưng tôi cần có khả năng thay đổi nội dung của các phần tử được lưu trữ bên trong. Ví dụ,
let mut ds = DataStruct{ inner: vec![1,2,3].into_boxed_slice() };
for x in ds {
*x += 1;
}
Trình biên dịch đang báo cho tôi lỗi về các vòng đời xung đột cho tham chiếu mà tôi đang cố gắng trả lại. Thời gian tồn tại mà tôi không mong đợi là phạm vi của next(&mut self)
hàm.
Nếu tôi cố gắng chú thích thời gian tồn tại vào next()
, thì thay vào đó, trình biên dịch sẽ nói với tôi rằng tôi chưa thỏa mãn đặc điểm của Iterator. Điều này có thể giải quyết được trong gỉ an toàn không?
Đây là lỗi:
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`
chỉnh sửa :
- thực hiện đã thay đổi
next()
để thứ tự lặp lại là một hoán vị của trình tự ban đầu.
Trả lời
Người kiểm tra khoản vay không thể chứng minh rằng các cuộc gọi tiếp theo next()
sẽ không truy cập vào cùng một dữ liệu. Lý do tại sao điều này là một vấn đề là bởi vì thời gian tồn tại của vay là trong suốt thời gian tồn tại của trình lặp, vì vậy nó không thể chứng minh rằng sẽ không có hai tham chiếu có thể thay đổi đến cùng một dữ liệu cùng một lúc.
Thực sự không có cách nào để giải quyết vấn đề này mà không có mã không an toàn - hoặc thay đổi cấu trúc dữ liệu của bạn. Bạn có thể thực hiện equlivant slice::split_at_mut
nhưng, do bạn không thể thay đổi dữ liệu ban đầu, bạn vẫn phải triển khai điều đó bằng mã không an toàn. Triển khai không an toàn có thể trông giống như sau:
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
}
}
}