iterator - 你如何实现一个迭代器,它的后继取决于术语的索引?

标签 iterator rust

我正在尝试实现一个迭代器,它产生序列 x^2、x^2+x、x^2+2x、x^2+3x... 对于常量(在调用时)参数 x,在 Rust 中。

据我所知,在实现的任何时候我必须处理的是 self.currself.next。在我看来,序列取决于序列中项目的索引。

struct SquareMultiple {
    // generates the sequence j = i^2, i^2+i, i^2+2i, i^2+3i, ...,
    curr: i64,
    next: i64,
}

// Implement `Iterator` for `SquareMultiple`.
// The `Iterator` trait only requires a method to be defined for the `next`
// element.
impl Iterator for SquareMultiple {
    type Item = i64;

    // Here, we define the sequence using `.curr` and `.next`.
    // The return type is `Option<T>`:
    //     * When the `Iterator` is finished, `None` is returned.
    //     * Otherwise, the next value is wrapped in `Some` and returned.
    fn next(&mut self) -> Option<I64> {

        // FIXME: What to do here?
        let new_next = self.curr + self.next;

        self.curr = self.next;
        self.next = new_next;

        // Since there's no endpoint to a SquareMultiple sequence, the
        // `Iterator` will never return `None`, and `Some` is always returned.
        Some(self.curr)
    }
}

// Returns a SquareMultiple sequence generator
fn squareseq() -> SquareMultiple {
    SquareMultiple { curr: 1, next: 2 }
}

我还考虑过使用 index 属性重载结构,但这在某种程度上似乎是对这种模式的滥用。

解决此问题的 Rustic 方法是什么?

最佳答案

使用rust 1.34

iter::successorsimpl trait ,这可以大大简化:

fn square_multiple(x: i64) -> impl Iterator<Item = i64> {
    std::iter::successors(Some(x * x), move |v| Some(v + x))
}

以前

您可以在实现Iterator 的结构中存储任何您想要的内容。对我来说,存储当前值和要递增的值似乎是最简单的。

struct SquareMultiple {
    curr: i64,
    inc: i64,
}

impl Iterator for SquareMultiple {
    type Item = i64;

    fn next(&mut self) -> Option<i64> {
        let val = self.curr;
        self.curr += self.inc;
        Some(val)
    }
}

impl SquareMultiple {
    fn new(x: i64) -> Self {
        SquareMultiple { curr: x * x, inc: x }
    }
}

fn main() {
    for i in SquareMultiple::new(5).take(10) {
        println!("{}", i);
    }
}

可能值得记录迭代器永远运行,因此当它超过 2^63 时会出现 panic 或回绕。

我喜欢这个解决方案,因为它根本不会成倍增加。出于某种原因,我的大脑认为加法比乘法“更容易”。


如果你真的需要使用索引,使用一个RangeFrommap它:

fn main() {
    let x = 5;
    let clever = (0..).map(|i| x * (x + i));
    for i in clever.take(10) {
        println!("{}", i);
    }
}

如果您需要一个单独的功能和最大性能(添加适当的音效),您可以创建一个新类型:

use std::ops::RangeFrom;

struct SquareMultiple {
    iter: RangeFrom<i64>,
    x: i64,
}

impl SquareMultiple {
    fn new(x: i64) -> Self {
        SquareMultiple {
            iter: (0..),
            x: x,
        }
    }
}

impl Iterator for SquareMultiple {
    type Item = i64;

    fn next(&mut self) -> Option<i64> {
        self.iter.next().map(|i| self.x * (self.x + i))
    }
}

fn main() {
    for i in SquareMultiple::new(5).take(10) {
        println!("{}", i);
    }
}

关于iterator - 你如何实现一个迭代器,它的后继取决于术语的索引?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36988470/

相关文章:

rust - 从切片构建固定大小数组的函数

java - 制作/实现数组列表的迭代器 - Java

c++ - 整个范围内的 std::for_each 没有方便的重载吗?

c++ - 按值/引用传递 vector 并从中获取迭代器

rust - 如果可能,我是否应该避免在Rust中使用Rc和RefCell?

multithreading - 无法跨mpsc::Sender作为字段发送跨线程结构

rust - 如何将特征与使用特征关联类型作为参数的超特征绑定(bind)?

c++ - 对同一对象的两次 size() 调用返回不同的值

PHP7 重命名迭代器内目录中的所有文件(Windows 10)64 位 XAMPP

rust - 如何在 Rust 中读写文本文件?