假设我们有一些existingIterator
迭代任意类型的元素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()
来实际“调用”迭代器,但它仍然不起作用。所以它归结为一个问题:我应该如何从模板构造/返回迭代器?