rust - 如何在包含可迭代项的结构上在 Rust 中定义迭代器?
问题描述
在 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),
}
}
}
简而言之,该结构Foo
包含两个向量,我想要一个在两个元素之间来回跳转的迭代器。当然,这里有很多错误,但核心是,我不明白如何创建一个包含项目迭代器的结构,foo
因为far
Rust 将迭代器定义为特征而不是类型。
解决方案
您必须在某些时候定义将产生什么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
为了避免动态类型并同时修复错误,让我们定义一些泛型类型:
// Iterator for the structure
struct FooIter<F, I> {
foo: F,
bar: I,
}
我们在我们的实现中添加了必要的Iterator
:
impl<F, I> Iterator for FooIter<F, I>
where
F: Iterator<Item = f64>,
I: Iterator<Item = i64>,
而且我们必须改变我们的生成方式FooIter
,这次我们将使用一个神奇的关键字impl
,这样可以避免编写Iterator
可能很长且不清楚的真实类型,编译器会为我们推断类型。此外,我们必须将类型绑定到的生命周期,&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(),
}
}
到这里我们完成了基础,下一个问题是你的代码没有产生Bar
type 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),
}
}
}
请注意,如果您仍然想要,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,
}
}
}
推荐阅读
- python - 如何在python中将字典转换为矩阵?
- swift - SwiftUI:如何让 TextField 成为第一响应者?
- delphi - Delphi - 如何正确注册自 XE8 以来的图形类?
- python - 被熊猫读取后删除CSV文件中的行
- php - php文件大小重要吗?
- django - 来自 API 更新的验证数据给出和空字典
- java - 如何在圆周上接近 pi
- android - 有没有办法在 AOSP 中禁用 HWC 并在 GLES 中执行所有操作?
- flutter - 无法在第一行安装稳定版 Flare 错误
- python - 设计一个字段值验证(不是 odoo.api.constrains 验证)