在 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 循环、变量范围的情况,在这些情况下跟踪状态要困难得多。
虽然我没有尝试这些,但我想有一些方法可以实现这一点,在大多数情况下都是不太理想的解决方法:
- 使用回调版本,构建一个向量,然后对其进行迭代...
(有效但违背了使用迭代器的目的,无法提前退出并避免为创建整个数据集例如)。 - 编写一个迭代器,该迭代器与使用与回调版本类似的逻辑的线程通信。
(虽然可能,但创建 OS 线程的开销使其在许多情况下成为一个糟糕的选择)。
除了上述解决方法:
有没有办法像给定的例子一样编写迭代器,逻辑更少?
理想情况下更像使用回调的例子。
否则还有其他方法可以处理吗?
或者这在 Rust 中根本不支持?
请注意,相同的逻辑适用于 Python 生成器(使用 yield 而不是回调,这里以回调为例,因为它们在一流函数中无处不在)。
最佳答案
C# 和 Python 等语言提供了一种从使用特殊 yield
关键字编写的方法生成迭代器的方法。从 Rust 1.11 开始,该语言中没有这样的功能。然而,这样的功能是计划中的(see RFC) (实际上,yield
is a reserved keyword!)并且可能会像在 C# 中一样工作(即编译器会生成一个结构,其中包含 Iterator
的必要状态和实现)。
在此期间,您可以尝试 Stateful ,一个试图提供此功能的项目。 (This blog post 解释了 Stateful 的工作原理以及所涉及的挑战。)
关于iterator - 编写支持多个逻辑分支的迭代器的最佳方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39137063/