我正在空间网格上实现光标,例如,对于空间[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。