如何实现一个迭代器,其后继取决于项的索引?

问题描述 投票:0回答:2

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

据我了解,在实施过程中的任何时候我必须处理的就是

self.curr
self.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
属性重载结构,但这似乎有点滥用这种模式。

乡村风格的做法是什么?

iterator rust
2个回答
2
投票

铁锈1.34

使用

iter::successors
impl 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 时会出现恐慌或回绕。

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


如果您确实需要使用索引,请使用

RangeFrom
map

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);
    }
}

0
投票

这里缺少使用

from_fn
的另一个相对简单的变体:

fn square_multiple(x: i64) -> impl Iterator<Item = i64> {
    let x2 = x * x;
    let mut v = -x;
    std::iter::from_fn(move || {
        v += x;
        Some(x2 + v)
    })
}

游乐场

© www.soinside.com 2019 - 2024. All rights reserved.