首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在包含可迭代项的结构上定义Rust中的迭代器?

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

Stack Overflow用户
提问于 2019-06-02 14:56:32
回答 1查看 1.2K关注 0票数 4

如何在包含已经可迭代的项的结构上定义Rust中的迭代器?下面是对迭代器的一次尝试

代码语言:javascript
复制
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包含两个向量,我想要一个在这两个元素之间随机来回跳跃的迭代器。当然,这里有很多错误,但在核心部分,我不知道如何创建一个结构来承载foofar项的迭代器,因为Rust将迭代器定义为特征而不是类型。

EN

回答 1

Stack Overflow用户

发布于 2019-06-05 17:29:07

@Stargateur在很大程度上对我进行了排序,但我想包括两个独立的代码来完成事情。以下是修复后的代码,它稍微接近于我最初的尝试,在Rust 1.34.1上工作:

代码语言:javascript
复制
// Structure of items
struct Foo {
    foo: Vec<f64>,
    far: Vec<i64>,
}

// Iterator for the structure
struct FooIter<FloatIter, IntIter>
where
    FloatIter: Iterator<Item = f64>,
    IntIter: Iterator<Item = i64>,
{
    foo: std::iter::Peekable<FloatIter>,
    far: std::iter::Peekable<IntIter>,
}

// Method that provides the iterator for use
impl Foo {
    fn iter<'a>(
        &'a self,
    ) -> FooIter<impl Iterator<Item = f64> + 'a, impl Iterator<Item = i64> + 'a> {
        FooIter {
            foo: self.foo.iter().cloned().peekable(),
            far: self.far.iter().cloned().peekable(),
        }
    }
}

// Item desired from iterator
enum Bar {
    MyFloat(f64),
    MyInt(i64),
}

// Implementation of the iterator
impl<FloatIter, IntIter> Iterator for FooIter<FloatIter, IntIter>
where
    FloatIter: Iterator<Item = f64>,
    IntIter: Iterator<Item = i64>,
{
    type Item = Bar;

    fn next(&mut self) -> Option<Bar> {
        match (self.foo.peek(), self.far.peek()) {
            (Some(_), Some(_)) => {
                if rand::random() {
                    self.foo.next().map(|x| Bar::MyFloat(x))
                } else {
                    self.far.next().map(|x| Bar::MyInt(x))
                }
            }
            (Some(_), None) => self.foo.next().map(|x| Bar::MyFloat(x)),
            (None, Some(_)) => self.far.next().map(|x| Bar::MyInt(x)),
            (None, None) => None,
        }
    }
}

// Iterate over a struct
fn main() {
    let fuz = Foo {
        foo: vec![1.2, 2.3, 3.4],
        far: vec![5, 6],
    };
    for item in fuz.iter() {
        match item {
            Bar::MyFloat(f) => println!("float : {}", f),
            Bar::MyInt(i) => println!("int : {}", i),
        }
    }
}

帮助我理解所发生的事情的是,FooIter在泛型类型上参数化了它的参数。这些类型是通过在Fooiter方法中的返回位置使用impl Trait来推断的。也就是说,我能够编写类似的代码,而不使用下面的推论:

代码语言:javascript
复制
extern crate rand;

// Structure of items
struct Foo {
    foo: Vec<f64>,
    far: Vec<i64>,
}

// Iterator for the structure
struct FooIter<'a> {
    foo: std::iter::Peekable<std::slice::Iter<'a, f64>>,
    far: std::iter::Peekable<std::slice::Iter<'a, i64>>,
}

// Method that provides the iterator for use
impl Foo {
    fn iter<'a>(&'a self) -> FooIter<'a> {
        FooIter {
            foo: self.foo.iter().peekable(),
            far: self.far.iter().peekable(),
        }
    }
}

// Item desired from iterator
enum Bar {
    MyFloat(f64),
    MyInt(i64),
}

// Implementation of the iterator
impl<'a> Iterator for FooIter<'a> {
    type Item = Bar;

    fn next(&mut self) -> Option<Bar> {
        match (self.foo.peek(), self.far.peek()) {
            (Some(_), Some(_)) => {
                if rand::random() {
                    self.foo.next().map(|x| Bar::MyFloat(x.clone()))
                } else {
                    self.far.next().map(|x| Bar::MyInt(x.clone()))
                }
            }
            (Some(_), None) => self.foo.next().map(|x| Bar::MyFloat(x.clone())),
            (None, Some(_)) => self.far.next().map(|x| Bar::MyInt(x.clone())),
            (None, None) => None,
        }
    }
}

// Iterate over a struct
fn main() {
    let fuz = Foo {
        foo: vec![1.2, 2.3, 3.4],
        far: vec![5, 6],
    };
    for item in fuz.iter() {
        match item {
            Bar::MyFloat(f) => println!("float : {}", f),
            Bar::MyInt(i) => println!("int : {}", i),
        }
    }
}

这几乎肯定是错误的做法,但我想看看这是否可能。我通过编译代码确定了迭代器类型:

代码语言:javascript
复制
fn main() {
    let x = vec![1.2, 2.3, 3.4];
    let y: i32 = x.iter().peekable();
}

这给了编译器错误:

代码语言:javascript
复制
error[E0308]: mismatched types
 --> junk.rs:4:19
  |
4 |     let y: i32 = x.iter().peekable();
  |                  ^^^^^^^^^^^^^^^^^^^ expected i32, found struct `std::iter::Peekable`
  |
  = note: expected type `i32`
             found type `std::iter::Peekable<std::slice::Iter<'_, {float}>>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0308`.

这包含了我正在寻找的类型。同样,这几乎肯定是错误的做法,但它帮助我理解了所提供的答案。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56412826

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档