如何使用“NonNull”实现“Iterator”来调整数组堆栈大小?

che*_*gpu 1 iterator rust

我正在按照指南使用以下方法来实现调整数组堆栈大小NonNull

pub struct ResizingStack<T> {
    a: NonNull<T>,
    n: usize,
    capacity: usize,
}
Run Code Online (Sandbox Code Playgroud)

现在基本功能(例如,pushpop)运行良好。完整的代码可以在这里找到。但我在实现这个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)

Lam*_*iry 5

无需使用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)

  • 如果您真的很欣赏并且找不到更多投票的方法,请将答案标记为“已接受”。:) 这也会让其他人知道这个问题有一个公认的答案。 (2认同)