创建一个Iterator
和成为一个Iterator
是有很大区别的。例如,Vec<char>
可以产生一个迭代器,但它本身不是一个迭代器。以下是两个简单的例子,希望您可以找到适合您使用情况的内容。
生成一个迭代器
对于您的情况,最简单的方法是为字段实现Deref
,让Vec<char>
处理它。或者,您可以编写一个包装函数来处理bar.iter()
。
pub struct Foo {
bar: Vec<char>,
}
impl Deref for Foo {
type Target = Vec<char>;
fn deref(&self) -> &Self::Target {
&self.bar
}
}
let foo = Foo { bar: vec!['a', 'b', 'c', 'd'] };
for x in foo.iter() {
println!("{:?}", x);
}
编写迭代器
以下是编写自己的迭代器用于 Vec<char>
的方法。请注意,Vec
存储为引用而不是拥有值。这是因为 Rust 可以解决生命周期约束。通过在迭代器的生命周期内保持一个不可变的引用,我们可以保证此迭代器生成的引用也可以持续存在于该生命周期中。如果我们使用拥有值,我们只能保证元素引用的生命周期持续到下一次对迭代器进行可变引用时。换句话说,每个值只能持续到再次调用 next
。但是,即使这也需要夜间功能才能正确表达。
pub struct SimpleIter<'a> {
values: &'a Vec<char>,
index: usize,
}
impl<'a> Iterator for SimpleIter<'a> {
type Item = &'a char;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.values.len() {
return None
}
self.index += 1;
Some(&self.values[self.index - 1])
}
}
这是一个将另一个迭代器包装起来的通用迭代器的简单示例。
struct Foo<I: ?Sized> {
bar: I,
}
impl<I: Iterator> Iterator for Foo<I> {
type Item = <I as Iterator>::Item;
fn next(&mut self) -> Option<Self::Item> {
println!("Iterating through Foo");
self.bar.next()
}
}
您还可以通过创建一个特征来更加精细地使用 Foo
。
pub trait IntoFoo {
fn iter_foo(self) -> Foo<Self>;
}
impl<T: Iterator> IntoFoo for T {
fn iter_foo(self) -> Foo<Self> {
Foo { bar: self }
}
}
let values = vec!['a', 'b', 'c', 'd'];
let foo: Foo<std::slice::Iter<'_, char>> = values.iter().iter_foo();
for x in foo {
println!("{:?}", x);
}
Deref
。这样,您就可以在不编写结构体包装器的情况下公开字段的方法(包括.iter()
)。 - Locke