如何在包含可迭代项的结构上在 Rust 中定义迭代器?

wye*_*r33 4 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),
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

简而言之,结构体Foo包含两个向量,我想要一个迭代器在两个元素之间随机来回跳跃。当然,这里有很多错误,但从本质上讲,我不明白如何创建一个结构来携带项目的迭代器foofar因为 Rust 将迭代器定义为 trait 而不是类型。

Sta*_*eur 5

你必须在某一点定义什么ItemIterator会产生,例如Iterator<Item = &'a f64>。让我们简化和改造到Iterator<Item = f64>,因为f64Copy那么它往往更好地避免参考,如果你不需要它。

所以,那么我们就会有编译错误:

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)