如何在Nim中实现支持tables.keys迭代器的map与min/max重载?
问题解答
1. 为什么接收iterable[T]作为参数的尝试1会失败?
iterable[T]并不是Nim中实际存在的运行时类型,它只是重载决议阶段的类型匹配标记,仅用来在重载函数时判断传入的参数是否可被for循环迭代,不能作为函数/迭代器的参数类型直接声明使用。
你在尝试1中直接定义iter: iterable[A],编译器无法将它和实际传入的迭代器类型绑定,自然也找不到对应的items迭代器实现,最终会报错找不到匹配的items过程。
2. 为什么尝试2的方案无法适配原生tables.keys?
Nim的迭代器分为两类,二者不能通用:
- 内联迭代器:编译期直接展开到调用位置,性能和手写循环一致,但没有独立的运行时表示,不能作为参数传递、也不能赋值给变量。原生
tables.keys就属于这类迭代器。 - 闭包迭代器:有独立的运行时实例,可以作为参数传递、赋值给变量,但有微小的性能开销。你自定义的
myKeys、还有尝试2中定义的Iterable[T]类型都属于闭包迭代器范畴。
尝试2的map只接收闭包迭代器作为参数,自然和内联实现的tables.keys类型不匹配,所以会报错。
3. 尝试2的写法是不是接收可迭代对象的标准方案?有没有替代方案?
尝试2是处理闭包迭代器的常用方案,但不是兼容所有可迭代对象的通用实现。如果需要同时兼容内联迭代器、序列、数组等所有可被for循环遍历的对象,基于模板的实现是更通用的标准方案。
模板会在编译期展开,可以直接接收内联迭代器作为参数,不需要将其转换为闭包迭代器,既兼容所有可迭代类型,也保留了内联迭代器的性能优势。
以下是可直接兼容原生tables.keys的实现示例:
import sequtils, sugar, tables # 通用map模板,支持所有可迭代类型 template map*(iter, fn): untyped = iterator impl: untyped = for x in iter: yield fn(x) impl() # 通用min模板,支持所有可迭代类型 template min*(iter): untyped = var first = true var res: typeof(iter[0]) for x in iter: if first: res = x first = false elif x < res: res = x if first: raise newException(ValueError, "cannot get min of empty iterable") res # 测试代码 var locations = initTable[(int, int), int]() locations[(1, 2)] = 1 locations[(2, 1)] = 2 locations[(-2, 5)] = 3 let minX = locations.keys.map(xy => xy[0]).min echo minX # 输出-2
内容的提问来源于stack exchange,提问作者Zecong Hu
相关产品推荐
相关产品推荐

