Rust'ta nasıl değiştirilebilir bir yineleyici oluşturabilirim? [çiftleme]
Güvenli Rust'ta değiştirilebilir bir yineleyici oluşturmaya çalışırken yaşamlar konusunda zorluk çekiyorum.
İşte sorunumu şu hale getirdim:
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
}
Yapısı DataStruct
asla değişmeyecek, ancak içinde depolanan öğelerin içeriğini değiştirebilmem gerekiyor. Örneğin,
let mut ds = DataStruct{ inner: vec![1,2,3].into_boxed_slice() };
for x in ds {
*x += 1;
}
Derleyici, döndürmeye çalıştığım referans için çakışan yaşam süreleri hakkında bana bir hata veriyor. Beklemediğimi bulduğu ömür, next(&mut self)
işlevin kapsamıdır .
Ömrünü açıklamaya çalışırsam next()
, bunun yerine derleyici bana Yineleyici özelliğini tatmin etmediğimi söyler. Bu güvenli pasla çözülebilir mi?
İşte hata:
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`
düzenlemeler :
next()
yineleme sırası orijinal dizinin bir permütasyonu olacak şekilde değiştirildi .
Yanıtlar
Ödünç alma denetleyicisi, sonraki çağrıların next()
aynı verilere erişmeyeceğini kanıtlayamaz . Bunun bir sorun olmasının nedeni, ödünç alma süresinin yineleyicinin ömrü boyunca olmasıdır, bu nedenle aynı verilere aynı anda iki değişken referans olmayacağını kanıtlayamaz.
Güvenli olmayan kod olmadan veya veri yapılarınızı değiştirmeden bunu çözmenin gerçekten bir yolu yoktur. Eşitliğini yapabilirsiniz, slice::split_at_mut
ancak orijinal verileri değiştiremeyeceğiniz için, bunu yine de güvenli olmayan kodda uygulamanız gerekir. Güvenli olmayan bir uygulama şunun gibi görünebilir:
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
}
}
}