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を使用し、コールバックはファーストクラス関数に遍在しているため、ここでは例としてコールバックを使用します)。
C#やPythonなどの言語は、特別なyield
キーワードを使用して記述されたメソッドからイテレーターを生成する方法を提供します。Rust 1.11の時点では、この言語にはそのような機能はありません。ただし、このような機能は計画されており(RFCを参照)(実際、yield
予約済みのキーワードです!)、C#と同様に機能する可能性があります(つまり、コンパイラーはに必要な状態と実装を備えた構造体を生成しますIterator
)。
それまでの間、この機能を提供しようとするプロジェクトであるステートフルを試すことができます。(このブログ投稿では、ステートフルの仕組みとそれに伴う課題について説明しています。)
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加