Cómo implementar `Iterator` para una pila de tamaño variable utilizando `NonNull`?
Estoy siguiendo la guía para implementar una pila de arreglo de redimensionamiento usando NonNull
:
rust
pub struct ResizingStack<T> {
a: NonNull<T>,
n: usize,
capacity: usize,
}
Ahora las funcionalidades básicas (por ejemplo, push
y pop
) funcionan bien. El código completo se puede encontrar aquí. Pero tengo problemas para implementar el rasgo Iterator
.
Para un iterador forward, una solución simple es hacer que ResizingStack
se comporte como una slice
.
rust
impl<T> Deref for Vec<T> {
type Target = [T];
fn deref(&self) -> &[T] {
unsafe {
std::slice::from_raw_parts(self.a.as_ptr(), self.n)
}
}
}
Sin embargo, una pila, de hecho, debería tener un iterador backward. Estos son mis intentos:
pub struct StackIter<'a, T> {
buf: &'a ResizingStack<T>,
index: usize,
}
impl<T> ResizingStack<T> {
pub fn iter(&self) -> StackIter<'_, T> {
StackIter {
buf: self,
index: self.n,
}
}
}
impl<'a, T> Iterator for StackIter<'a, T> {
type Item = &'a T;
<pre><code>fn next(&mut self) -> Option<Self::Item> {
if self.index == 0 {
None
} else {
let item;
unsafe {
item = Some(ptr::read(self.buf.a.as_ptr().add(self.index - 1)));
self.index -= 1;
}
item // ERROR: expected `Option<&T>`, but found `Option<T>`.
}
}
</code></pre>
}
davy.ai
Solución para el Iterador ResizingStack
Para implementar un iterador hacia atrás para una implementación de
ResizingStack
, podemos definir un tipoStackIter
que contenga el búfer y el índice actual. El métodoiter
enResizingStack
devuelve unStackIter
que comienza en el último elemento del búfer.El método
next
enStackIter
puede iterar hacia atrás disminuyendo el índice en cada llamada hasta que llegue al primer elemento. Podemos usar el métodoadd
en punteros para acceder al elemento en el índice actual. Sin embargo, debemos tener cuidado de no mover los datos fuera del búferResizingStack
. Podemos envolver el elemento con un tipoOption
para evitar mover los datos.El método
next
devuelve unOption<option<&'a t="">>
, donde el innerOption
se utiliza para evitar mover los datos fuera del búfer. El outerOption
se utiliza para indicar cuándo el iterador ha llegado al final del búfer. El bloqueunsafe
es necesario para leer el elemento en el índice actual sin moverlo fuera del búfer.Con estos cambios, ahora podemos iterar hacia atrás sobre un
ResizingStack
utilizando un buclefor
, un buclewhile let
o cualquier otra construcción que admita la iteración.Esto imprimirá:
Some(&3)
</option<&’a>Some(&2)
Some(&1)