In Rust, come creo un iteratore mutabile? [duplicare]
Ho difficoltà con le vite quando provo a creare un iteratore mutevole in Rust sicuro.
Ecco a cosa ho ridotto il mio problema:
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
}
La struttura del mio DataStruct
non cambierà mai, ma devo essere in grado di mutare i contenuti degli elementi immagazzinati al suo interno. Per esempio,
let mut ds = DataStruct{ inner: vec![1,2,3].into_boxed_slice() };
for x in ds {
*x += 1;
}
Il compilatore mi sta dando un errore sulle durate in conflitto per il riferimento che sto cercando di restituire. La durata che trova che non mi aspetto è l'ambito della next(&mut self)
funzione.
Se provo ad annotare la durata su next()
, il compilatore, invece, mi dice che non ho soddisfatto il tratto Iterator. È risolvibile in ruggine sicura?
Ecco l'errore:
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`
modifiche :
- modificata l'implementazione di in
next()
modo che l'ordine di iterazione sia una permutazione della sequenza originale.
Risposte
Il controllore del prestito non è in grado di dimostrare che le chiamate successive a next()
non accedono agli stessi dati. Il motivo per cui questo è un problema è perché la durata del prestito è per la durata della vita dell'iteratore, quindi non può dimostrare che non ci saranno due riferimenti mutabili agli stessi dati allo stesso tempo.
Non c'è davvero un modo per risolvere questo problema senza codice non sicuro o senza modificare le strutture dei dati. Potresti fare l'equivalente di slice::split_at_mut
ma, dato che non puoi modificare i dati originali, dovresti comunque implementarlo in un codice non sicuro. Un'implementazione non sicura potrebbe essere simile a questa:
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
}
}
}