Dans Rust, comment créer un itérateur mutable? [dupliquer]
J'ai des difficultés avec la durée de vie en essayant de créer un itérateur mutable dans Rust sécurisé.
Voici à quoi j'ai réduit mon problème:
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 structure de mon DataStruct
ne changera jamais, mais je dois être capable de muter le contenu des éléments stockés à l'intérieur. Par exemple,
let mut ds = DataStruct{ inner: vec![1,2,3].into_boxed_slice() };
for x in ds {
*x += 1;
}
Le compilateur me donne une erreur sur les durées de vie conflictuelles pour la référence que j'essaie de renvoyer. La durée de vie à laquelle je ne m'attends pas correspond à la portée de la next(&mut self)
fonction.
Si j'essaie d'annoter la durée de vie next()
, le compilateur me dit à la place que je n'ai pas satisfait le trait Iterator. Est-ce soluble dans la rouille sûre?
Voici l'erreur:
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`
modifications :
- mise en œuvre modifiée de
next()
afin que l'ordre d'itération soit une permutation de la séquence d'origine.
Réponses
Le vérificateur d'emprunt ne peut pas prouver que les appels ultérieurs à next()
n'accéderont pas aux mêmes données. La raison pour laquelle c'est un problème est que la durée de vie de l'emprunt correspond à la durée de vie de l'itérateur, il ne peut donc pas prouver qu'il n'y aura pas deux références mutables aux mêmes données en même temps.
Il n'y a vraiment pas de moyen de résoudre ce problème sans code non sécurisé - ou sans modifier vos structures de données. Vous pouvez faire l'équlivant de slice::split_at_mut
mais, étant donné que vous ne pouvez pas muter les données d'origine, vous devrez de toute façon implémenter cela dans un code non sécurisé. Une implémentation non sécurisée pourrait ressembler à ceci:
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
}
}
}