[英]How to implement IntoIterator on a StackVec
我正在尝试编写一个像 object 这样的Vec
,其大小固定,可在堆栈上使用。
这是我正在尝试完成作业 1,阶段 2A的在线课程的一部分。
我在实现IntoIterator
特征时遇到问题。
StructVec
的代码
#![no_std]
pub struct StackVec<'a, T: 'a> {
storage: &'a mut [T],
len: usize
}
impl<'a, T: 'a> StackVec<'a, T> {
pub fn new(storage: &'a mut [T]) -> StackVec<'a, T> {
StackVec { storage, len: 0 }
}
pub fn with_len(storage: &'a mut [T], len: usize) -> StackVec<'a, T> {
StackVec { storage, len }
}
pub fn capacity(&self) -> usize {
self.storage.len()
}
pub fn truncate(&mut self, len: usize) {
if len < self.len {
self.len = len;
}
}
pub fn into_slice(self) -> &'a mut [T] {
&mut self.storage[..self.len]
}
pub fn as_slice(&self) -> &[T] {
&self.storage[..self.len]
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
&mut self.storage[..self.len]
}
pub fn len(&self) -> usize {
self.len
}
pub fn is_empty(&self) -> bool {
self.len == 0
}
pub fn is_full(&self) -> bool {
self.len == self.storage.len()
}
pub fn push(&mut self, value: T) -> Result<(), ()> {
if self.is_full() {
return Err(());
}
self.storage[self.len] = value;
self.len += 1;
Ok(())
}
}
我能够通过返回底层数组的迭代器来实现IntoIterator
特征:
impl<'a, T: 'a> IntoIterator for StackVec<'a, T> {
type Item = &'a mut T;
type IntoIter = core::slice::IterMut<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.storage.into_iter()
}
}
然而,这并不是我真正想要的,因为它会遍历整个数组,而不仅仅是推送到它上面的项目。
我尝试从底层数组的数组切片中返回一个迭代器,但我被生命周期所吸引:
impl<'a, T: 'a> IntoIterator for StackVec<'a, T> {
type Item = &'a T;
type IntoIter = core::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
self.as_slice().into_iter()
}
}
编译失败,报错
error[E0597]: `self` does not live long enough
--> src/lib.rs:165:9
|
165 | self.as_slice().into_iter()
| ^^^^ borrowed value does not live long enough
166 | }
| - borrowed value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 160:1...
--> src/lib.rs:160:1
|
160 | / impl<'a, T: 'a> IntoIterator for StackVec<'a, T> {
161 | | type Item = &'a T;
162 | | type IntoIter = core::slice::Iter<'a, T>;
163 | |
... |
166 | | }
167 | | }
| |_^
我也尝试过完全创建一个新的Iterator
,但我又被抓住了!
struct Iter<'a, T: 'a> {
stack_vec: StackVec<'a, T>,
start: usize,
}
impl<'a, T: 'a> Iterator for Iter<'a, T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
let start = self.start;
if start < self.stack_vec.len {
self.start += 1;
Some(self.stack_vec[start])
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.stack_vec.len - self.start;
(size, Some(size))
}
}
编译失败,报错:
error[E0508]: cannot move out of type `[T]`, a non-copy slice
--> src/lib.rs:148:18
|
148 | Some(self.stack_vec[start])
| ^^^^^^^^^^^^^^^^^^^^^ cannot move out of here
我试过查看做同样事情的板条箱,但要么他们使用我不能用于这个任务的std
库,要么我不明白如何将他们的代码移植到我的。
https://github.com/bluss/arrayvec
https://github.com/danielhenrymantilla/stackvec-rs/blob/master/src/stackvec/traits/into_iter.rs
我究竟做错了什么?
作为您最初想法的一个相当简单的扩展,您可以使用take
方法限制迭代器可以返回的元素数量。 这会将您的IntoIterator
实现变为:
impl<'a, T: 'a> IntoIterator for StackVec<'a, T> {
type Item = &'a mut T;
type IntoIter = std::iter::Take<core::slice::IterMut<'a, T>>;
fn into_iter(self) -> Self::IntoIter {
self.storage.into_iter().take(self.len)
}
}
您在其他尝试实现IntoIterator
时遇到了问题,因为into_iter
方法获得了self
的所有权。 这意味着一旦 function 退出,您需要确保已将要在迭代器中使用的所有内容从self
中移出或复制。 由于as_slice
仅借用,因此您不能从 function 将迭代器返回到切片(它借用的数据将被删除)。
impl<'a, T: 'a> IntoIterator for StackVec<'a, T> {
type Item = &'a T;
type IntoIter = core::slice::Iter<'a, T>;
fn into_iter(self) -> Self::IntoIter {
// ^ no & or &mut here means this function takes ownership of self
self.as_slice().into_iter()
}
}
您仍然可以创建StackVec
结构的非拥有迭代器,但您不会使用IntoIterator
来执行此操作。 相反,只需在您的结构上创建一个名为iter
的方法:
pub fn iter(&self) -> impl Iterator<Item=&T> {
self.storage.iter().take(self.len)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.