В какой-то момент вы должны определить, что 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
типа next()
, поэтому мы должны исправить ваш код, также было бы неплохо создать генератор случайных чисел propre.Итак, вот последний фрагмент:
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,
}
}
}