如何使用 `NonNull` 为调整大小的数组堆栈实现 `Iterator`?
How to implement `Iterator` for a resizing array stack using `NonNull`?
我正在按照 guide 使用 NonNull
:
实现调整大小的数组堆栈
pub struct ResizingStack<T> {
a: NonNull<T>,
n: usize,
capacity: usize,
}
现在基本功能(例如 push
和 pop
)运行良好。完整代码可见here。但是我在实现 Iterator
特征时遇到了一些麻烦。
对于 forward 迭代器,一个简单的解决方案是让 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)
}
}
}
然而,事实上,一个栈应该有一个backward迭代器。以下是我的尝试:
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>`.
}
}
}
没有必要对产生 &T
.
的迭代器使用 unsafe
代码
这是一个使用 .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)
}
}
或者,这是一个包装 .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()
}
}
在这一点上,我们不妨直接放弃包装器和 return 适配器:
impl<T> ResizingStack<T> {
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a T> {
self.deref().iter().rev()
}
}
我正在按照 guide 使用 NonNull
:
pub struct ResizingStack<T> {
a: NonNull<T>,
n: usize,
capacity: usize,
}
现在基本功能(例如 push
和 pop
)运行良好。完整代码可见here。但是我在实现 Iterator
特征时遇到了一些麻烦。
对于 forward 迭代器,一个简单的解决方案是让 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)
}
}
}
然而,事实上,一个栈应该有一个backward迭代器。以下是我的尝试:
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>`.
}
}
}
没有必要对产生 &T
.
unsafe
代码
这是一个使用 .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)
}
}
或者,这是一个包装 .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()
}
}
在这一点上,我们不妨直接放弃包装器和 return 适配器:
impl<T> ResizingStack<T> {
pub fn iter<'a>(&'a self) -> impl Iterator<Item = &'a T> {
self.deref().iter().rev()
}
}