什么是编写支持多个逻辑分支的迭代器的最佳方法?

时间:2016-08-25 05:07:30

标签: iterator rust

在Rust中,我开始编写迭代器,从带有回调函数的代码转换它们。

我遇到的问题是,在函数的多个分支中使用回调的代码没有如此干净地转换为Rust迭代器。

给出一些伪代码。

// function using callbacks where the caller can exit at any time,
// can be used in a similar way to an iterator.
fn do_stuff(args, callback_fn(cb_args)) {
    // define a, b, c... args
    if callback_fn(a, b, 0) == false { return; }
    for i in 0..n {
        if callback_fn(c, d, i) == false { return; }
    }
    if callback_fn(e, f, -1) == false { return; }
}

将此转换为迭代器是相当尴尬的,因为我需要存储一些代表每个分支的状态。

impl Iterator for MyStruct {
    fn next(&mut self) -> Option<MyResult> {
        let out = match (self.state) {
            0 => {
                self.state += 1;
                Some(MyResult(self.a, self.b, 0))
            },
            1 => {
                self.i += 1;
                if self.i == self.n {
                    self.state += 1;
                }
                Some(MyResult(self.c, self.d, self.i - 1))
            },
            2 => {
                self.state += 1;
                Some(MyResult(self.e, self.f, -1))
            },
            _ => {
                None
            },
        }
        return out;
    }
// --- snip

通过上面的例子,这可以说是可以接受的(如果有点尴尬)。考虑具有多个for循环,可变范围的情况,其中更难跟踪状态。

虽然我没有尝试这些,但我想有一些方法可以达到这个目的,在大多数情况下,这些方法都不那么理想:

  • 使用回调版本,构建一个向量,然后迭代它...
    (但是工作但是无法使用迭代器,无法提前退出并避免创建整个数据集例如)。
  • 编写一个迭代器,它与使用与回调版本类似的逻辑的线程进行通信。
    (尽管可能,创建操作系统线程的开销在很多情况下使其成为一个糟糕的选择)。

除了上面的解决方法:

是否有方法可以编写迭代器,如给定的示例,逻辑更少??理想情况下更像是使用回调的示例。
否则还有其他方法可以解决这个问题吗?

或者这在Rust中不受支持吗?

注意,同样的逻辑适用于来自Python生成器(使用yield而不是回调,在这里使用回调作为示例,因为它们无处不在于第一类函数)。

1 个答案:

答案 0 :(得分:5)

C#和Python等语言提供了一种从使用特殊yield关键字编写的方法生成迭代器的方法。从Rust 1.11开始,该语言中没有这样的功能。但是,这样的功能是计划(see RFC)(实际上是yield is a reserved keyword!)并且可能在C#中起作用(即编译器将生成具有Iterator的必要状态和实现的结构)

与此同时,您可以尝试Stateful,这是一个尝试提供此功能的项目。 (This blog post解释了有状态如何运作以及所涉及的挑战。)