在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而不是回调,在这里使用回调作为示例,因为它们无处不在于第一类函数)。
答案 0 :(得分:5)
C#和Python等语言提供了一种从使用特殊yield
关键字编写的方法生成迭代器的方法。从Rust 1.11开始,该语言中没有这样的功能。但是,这样的功能是计划(see RFC)(实际上是yield
is a reserved keyword!)并且可能在C#中起作用(即编译器将生成具有Iterator
的必要状态和实现的结构)
与此同时,您可以尝试Stateful,这是一个尝试提供此功能的项目。 (This blog post解释了有状态如何运作以及所涉及的挑战。)