有可能用借来的项实现迭代器吗



我正在空间网格上实现光标,例如,对于空间[2, 2],光标应分别访问[0, 0][1, 0][0, 1][1, 1]。我在下面写了代码,但当我使用for cursor in SpaceCursor::<2>::new(&[2, 2])时,我注意到光标不是借来的,而是复制的。由于光标将始终处于SpaceCursor生存期内,我想知道是否可以使用其类型&[i32; 2]而不是[i32; 2]

struct SpaceCursor<const D: usize> {
cursor: [i32; D],
boundary: [usize; D],
}
impl<const D: usize> SpaceCursor<D> {
pub fn new(boundary: &[usize]) -> Self {
let mut result = SpaceCursor::<D> {
cursor: [0; D],
boundary: boundary.try_into().expect("Bad boundary"),
};
if D >= 1 {
result.cursor[0] = -1;
}
result
}
}
impl<const D: usize> Iterator for SpaceCursor<D> {
type Item = [i32; D];
fn next(&mut self) -> Option<Self::Item> {
let mut index = 0;
while index < D {
self.cursor[index] += 1;
if self.cursor[index] < self.boundary[index] as i32 {
break;
}
index += 1;
}
if index == D {
None
} else {
for i in 0..index {
self.cursor[i] = 0;
}
Some(self.cursor)
}
}
}

如果需要迭代器来产生引用,那么迭代器本身必须包含对底层数据的引用。这是由于Iterator特性的设计:

trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}

当实现Iterator时,其中Item是一个引用,您需要给它一个生存期。但您只需要选择一个生存期,该生存期必须对所有项都有效,并且该生存期的寿命必须超过迭代器。只有当所有项都已保存在内存中的某个位置,并且寿命将超过迭代器的使用时间时,这才有效。

在Rust 1.65中,这将(有点(改变。一个新的功能,通用关联类型(GATs(,将在稳定中提供,这将允许您定义一个";流式传输";像这样的迭代器:

trait StreamingIterator {
type Item<'a> where Self: 'a;
fn stream_next<'a>(&'a mut self) -> Option<Self::Item<'a>>;
}

这里的区别在于,对于stream_next的每次调用都会实例化生存期'a,因此每次都可能不同。调用方还可以选择保留引用的时间,并且仅受流迭代器本身的可变借用的限制。可变性还意味着你一次只能借用一个项目,所以你不能在不克隆它们的情况下把它们收集到Vec中。

你的迭代器可以这样移植:

impl<const D: usize> StreamingIterator for SpaceCursor<D> {
type Item<'a> = &'a [i32; D];
fn stream_next<'a>(&'a mut self) -> Option<Self::Item<'a>> {
let mut index = 0;
while index < D {
self.cursor[index] += 1;
if self.cursor[index] < self.boundary[index] as i32 {
break;
}
index += 1;
}
if index == D {
None
} else {
for i in 0..index {
self.cursor[i] = 0;
}
Some(&self.cursor)
}
}
}

注意;"限制";一次只能借用一个项目,这对这项工作非常关键,因为您正在覆盖cursor值。这也应该是另一个提示,说明为什么这不适用于非流式Iterator特性。

由于StreamingIterator不是一个内置特性,因此在循环中没有语法支持,因此必须显式使用它:

let data = vec![1,3,7,9];
let mut cursor = SpaceCursor::<4>::new(&data);
while let Some(i) = cursor.stream_next() {
println!("{i:?}"); 
}

您现在可以在Rust 1.64测试版中每晚试用,或者等待大约2周才能获得Rust 1.65。

最新更新