existingIterator
任意の type の要素を反復処理するものがあると仮定しましょうT
。私が今達成したいのはexistingIterator
、変更された動作を使用してから新しい反復子を派生させることです。次のような例を考えてください。
- 元の反復子の長さを制限します
existingIterator.take(n)
。 - 要素のマッピング。たとえば、
existingIterator.map(modifier)
- などの特定の要素をフィルタリングし
existingIterator.filter(predicate)
ます。
これらすべてのケースで、次のようなことができるように、さらに別のイテレータを作成したいだけです。
for x in existingIterator.filter(something)
.map(modifier)
.take(10):
...
私の一般的な問題は次のとおりです。既存のイテレータを取り、変更されたイテレータを返す汎用イテレータまたはテンプレートをどのように作成できますか?
フォローアップの質問は、なぜそのような重要な機能が標準ライブラリにないのかということです-何かが足りないのでしょうか?
これが私が試したことです:
試行 1
take(n)
機能を例に挙げてみましょう。私の最初のアプローチは、通常のジェネリックを使用することでしたiterator
:
iterator infinite(): int {.closure.} =
var i = 0
while true:
yield i
inc i
iterator take[T](it: iterator (): T, numToTake: int): T {.closure.} =
var i = 0
for x in it():
if i < numToTake:
yield x
inc i
for x in infinite.take(10):
echo x
これはコンパイルされますが、残念ながら実際には機能しません: (1) 要素が適切に反復されていません (それらはすべてゼロです。おそらくバグでしょうか? )、(2) 私のプログラムが無限ループに陥っているように見えます。 (3) クロージャ イテレータに対してのみ機能します。つまり、任意のイテレータをラップすることはできません。
試行 2
クロージャ イテレータに対する制限は、この問題が実際にテンプレート ソリューションを必要とすることを示唆しています。
template take[T](it: iterator(): T, numToTake: int): expr {.immediate.} =
var i = 0
iterator tmp(): type(it()) =
for item in it:
if i < numToTake:
yield item
inc i
tmp
これはほとんど機能しているように見えます (つまり、テンプレートがコンパイルされます)。ただし、今電話すると、次のようfor x in infinite.take(10)
になります。
`Error: type mismatch: got (iterator (): int{.closure, gcsafe, locks: 0.})`
実際にイテレータを「呼び出す」ためにa を追加しようとしました()
が、それでも機能しません。したがって、問題は次のとおりです。テンプレートからイテレータを作成/返すにはどうすればよいですか?