【发布时间】:2015-06-17 18:16:07
【问题描述】:
假设我们有一些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)元素没有正确迭代(它们都只是零,可能是bug?),(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.})`
我试图附加一个() 来实际“调用”迭代器,但它仍然不起作用。所以归结为一个问题:我应该如何从模板构造/返回迭代器?
【问题讨论】:
-
有一个open issue 可能与此问题有关。
-
Jon Skeet 有一篇关于在 C# 中为 LINQ 执行此操作的优秀博客文章系列 - 这与您正在做的事情非常相似(尽管使用另一种语言),但总体思路相同。
-
为什么他们不能称这种语言为别的该死的东西,看到我的名字出现在他们身上真是令人困惑..:/
-
@Nim:至少不像约翰。或者朱莉娅:)。
标签: templates iterator nim-lang