我正在按照指南使用以下方法来实现调整数组堆栈大小NonNull
:
pub struct ResizingStack<T> {
a: NonNull<T>,
n: usize,
capacity: usize,
}
Run Code Online (Sandbox Code Playgroud)
现在基本功能(例如,push
和pop
)运行良好。完整的代码可以在这里找到。但我在实现这个Iterator
特性时遇到了一些麻烦。
对于前向迭代器,一个简单的解决方案是ResizingStack
强制执行slice
.
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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
然而,实际上,堆栈应该有一个向后迭代器。以下是我的尝试:
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;
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>`.
}
}
}
Run Code Online (Sandbox Code Playgroud)
无需使用unsafe
生成 的迭代器代码&T
。
这是一个使用的解决方案.split_last()
:
pub struct StackIter<'a, T> {
buf: &'a [T],
}
impl<'a, T> Iterator for StackIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
let (last, remainder) = self.buf.split_last()?;
self.buf = remainder;
Some(last)
}
}
Run Code Online (Sandbox Code Playgroud)
或者,这是一个包装的解决方案.rev()
:
use std::{iter::Rev, slice};
pub struct StackIter<'a, T> {
inner: Rev<slice::Iter<'a, T>>,
}
impl<'a, T> Iterator for StackIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
Run Code Online (Sandbox Code Playgroud)
此时,我们不妨放弃包装器并直接返回适配器:
impl<T> ResizingStack<T> {
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a T> {
self.deref().iter().rev()
}
}
Run Code Online (Sandbox Code Playgroud)