如何在 Rust 中在包含可迭代项的结构上定义迭代器?这是迭代器的一次尝试
use rand;
// Structure of items
struct Foo {
foo: Vec<f64>,
bar: Vec<i64>,
}
// Iterator for the structure
struct FooIter {
foo: Iterator,
bar: Iterator,
}
// Method that provides the iterator for use
impl Foo {
fn iter(&self) -> FooIter {
FooIter {
foo: self.foo.iter().peek(),
bar: self.bar.iter().peek(),
}
}
}
// Item desired from iterator
enum Bar {
MyFloat(f64),
MyInt(i64),
}
// Implementation of the iterator
impl Iterator for FooIter {
type Item = Bar;
fn next(&mut self) -> Option<Bar> {
match (self.foo.peek(), self.far.peek()) {
(Some(_), Some(_)) => {
if rand::random() {
self.foo.next()
} else {
self.bar.next()
}
}
(Some(_), None) => self.foo.next(),
(None, Some(_)) => self.bar.next(),
(None, None) => None,
}
}
}
// Iterate over a struct
fn main() {
let fuz = Foo {
foo: vec![1.2, 2.3, 3.4],
bar: vec![5, 6],
};
for item in fuz.iter() {
match item {
Bar::MyFloat(f) => println!("float : {}", f),
Bar::MyInt(i) => println!("int : {}", i),
}
}
}
Run Code Online (Sandbox Code Playgroud)
简而言之,结构体Foo包含两个向量,我想要一个迭代器在两个元素之间随机来回跳跃。当然,这里有很多错误,但从本质上讲,我不明白如何创建一个结构来携带项目的迭代器foo,far因为 Rust 将迭代器定义为 trait 而不是类型。
你必须在某一点定义什么Item的Iterator会产生,例如Iterator<Item = &'a f64>。让我们简化和改造到Iterator<Item = f64>,因为f64是Copy那么它往往更好地避免参考,如果你不需要它。
所以,那么我们就会有编译错误:
error[E0277]: the size for values of type `(dyn std::iter::Iterator<Item = f64> + 'static)` cannot be known at compilation time
--> src/main.rs:11:5
|
11 | foo: std::iter::Iterator<Item = f64>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `(dyn std::iter::Iterator<Item = f64> + 'static)`
= note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: only the last field of a struct may have a dynamically sized type
Run Code Online (Sandbox Code Playgroud)
为了避免动态类型并同时修复错误,让我们定义一些泛型类型:
// Iterator for the structure
struct FooIter<F, I> {
foo: F,
bar: I,
}
Run Code Online (Sandbox Code Playgroud)
我们在我们的实现中添加了必要的Iterator:
impl<F, I> Iterator for FooIter<F, I>
where
F: Iterator<Item = f64>,
I: Iterator<Item = i64>,
Run Code Online (Sandbox Code Playgroud)
而且我们必须改变我们的生成方式FooIter,这次我们将使用一个magic关键字impl,这样可以避免写出Iterator可能很长且不清楚的真实类型,编译器会为我们推断类型。此外,我们必须将类型绑定到 of 的生命周期,&self因为只要迭代器存在,它就必须借用,只需声明'a生命周期并添加即可+ 'a:
fn iter<'a>(
&'a self,
) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
FooIter {
foo: self.foo.iter().copied(),
bar: self.bar.iter().copied(),
}
}
Run Code Online (Sandbox Code Playgroud)
到这里我们完成了基本的,下一个问题是你的代码没有产生Bartype in next(),所以我们必须更正你的代码,另外创建一个适当的随机生成器会很好。所以这里是最后的片段:
use rand::{rngs::ThreadRng, thread_rng, Rng};
// Structure of items
struct Foo {
foo: Vec<f64>,
bar: Vec<i64>,
}
// Iterator for the structure
struct FooIter<'r, F, I> {
foo: F,
bar: I,
rng: &'r mut ThreadRng,
}
// Method that provides the iterator for use
impl Foo {
fn iter<'a, 'r: 'a>(
&'a self,
rng: &'r mut ThreadRng,
) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
FooIter {
foo: self.foo.iter().copied(), // nigthly feature, use cloned() for stable
bar: self.bar.iter().copied(),
rng,
}
}
}
// Item desired from iterator
enum Bar {
MyFloat(f64),
MyInt(i64),
}
// Implementation of the iterator
impl<'r, F, I> Iterator for FooIter<'r, F, I>
where
F: Iterator<Item = f64>,
I: Iterator<Item = i64>,
{
type Item = Bar;
fn next(&mut self) -> Option<Bar> {
if self.rng.gen() {
self.foo
.next()
.map(|x| Bar::MyFloat(x))
.or_else(|| self.bar.next().map(|x| Bar::MyInt(x)))
} else {
self.bar
.next()
.map(|x| Bar::MyInt(x))
.or_else(|| self.foo.next().map(|x| Bar::MyFloat(x)))
}
}
}
// Iterate over a struct
fn main() {
let fuz = Foo {
foo: vec![1.2, 2.3, 3.4],
bar: vec![5, 6],
};
for item in fuz.iter(&mut thread_rng()) {
match item {
Bar::MyFloat(f) => println!("float : {}", f),
Bar::MyInt(i) => println!("int : {}", i),
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您仍然想要一个,Peekable<Iterator>那么只需执行以下操作:
struct FooIter<'r, F, I>
where
F: Iterator<Item = f64>,
I: Iterator<Item = i64>,
{
foo: Peekable<F>,
bar: Peekable<I>,
rng: &'r mut ThreadRng,
}
// Method that provides the iterator for use
impl Foo {
fn iter<'a, 'r: 'a>(
&'a self,
rng: &'r mut ThreadRng,
) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
FooIter {
foo: self.foo.iter().copied().peekable(),
bar: self.bar.iter().copied().peekable(),
rng,
}
}
}
Run Code Online (Sandbox Code Playgroud)