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ジェネレータ(これらは第一級関数と遍在しているのでここでは例として、コールバックを使用して、代わりにコールバックの収率を用いて)からの適用。 C#やPythonのような
if-elseの代わりに 'match'を使用し、' return'を省略すると、コードがより素早くなります(https://gist.github。com/LukasKalbertodt/9f2e73305880e586231b76ef4b6a948c)既にそうですか? :) –
@LukasKalbertodt、右は、一致を使用するように編集されていますが、これは問題の根本には触れません。コールバックをイテレータに使用する複雑な関数を移動することは些細なことではありません。例えばhttps://gitlab.com/ideasman42/rust-simple-examples/blob/master/draw_poly_2d_callback/src/main.rsを維持してください。 – ideasman42