No Rust, como faço para criar um iterador mutável? [duplicado]
Estou tendo dificuldade com vidas úteis ao tentar criar um iterador mutável no Rust seguro.
Aqui está o que eu reduzi meu problema a:
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
}
A estrutura do meu DataStruct
nunca mudará, mas preciso ser capaz de modificar o conteúdo dos elementos armazenados nele. Por exemplo,
let mut ds = DataStruct{ inner: vec![1,2,3].into_boxed_slice() };
for x in ds {
*x += 1;
}
O compilador está me dando um erro sobre tempos de vida conflitantes para a referência que estou tentando retornar. O tempo de vida que ele descobre que não estou esperando é o escopo da next(&mut self)
função.
Se tento anotar o tempo de vida next()
, o compilador, em vez disso, me diz que não satisfiz o traço Iterator. Isso pode ser resolvido em caso de ferrugem segura?
Aqui está o erro:
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`
edições :
- implementação alterada de
next()
para que a ordem da iteração seja uma permutação da sequência original.
Respostas
O verificador de empréstimo não consegue provar que as chamadas subsequentes para next()
não acessarão os mesmos dados. A razão pela qual isso é um problema é porque a vida útil do empréstimo é a duração da vida útil do iterador, então não pode provar que não haverá duas referências mutáveis para os mesmos dados ao mesmo tempo.
Realmente não há uma maneira de resolver isso sem código inseguro - ou alterando suas estruturas de dados. Você poderia fazer o equivalente a slice::split_at_mut
, mas, dado que você não pode alterar os dados originais, você teria que implementar isso em um código inseguro de qualquer maneira. Uma implementação insegura pode ser semelhante a esta:
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
}
}
}