如何将任意迭代器作为函数参数?为何自定义迭代器可用而pairs不行?
为何自定义walk函数能接收自定义迭代器,却无法传入pairs?
问题
我编写了一个通用的walk函数,为何可以传入自定义迭代器,却无法传入pairs?
示例
以下是一个简单的walk函数,用于处理src中的每个元素:
function walk(src) for n,i in src do print(n, i[1]+i[#i]) end end
当用walk(items(x))调用时,函数运行正常:
function items(lst, n) n=0 return function() if lst and n < #lst then n=n+1 return n,lst[n] end end end x={ {1,2}, {3,4}, {5,6}, {5,6} } walk(items(x)) --> 输出 (1,3),(2,7),(3,11)等
但尝试传入pairs(x)时,程序崩溃:
walk(pairs(x))
报错信息:
lua: x.lua: bad argument #1 to 'for iterator' (table expected, got nil) stack traceback: [C]: in function 'next' x.lua:7: in function 'walk' x.lua:31: in main chunk [C]: in ?
核心区别:两类迭代器的返回格式不同
Lua的迭代器分为两类,你的items和pairs分属不同类型,而walk函数只适配了其中一种:
自定义
items是闭包迭代器items函数返回的是一个单独的闭包函数,迭代所需的状态(列表lst和计数n)都保存在闭包内部。当for n,i in src执行时,Lua会直接重复调用这个闭包,每次调用返回下一组值,直到返回nil终止迭代。这种场景下,src只需要是一个函数,完全符合你walk函数的参数预期。pairs是无状态迭代器pairs实际上会返回三个值:迭代函数next、要遍历的目标表x、初始状态nil。Lua的for循环处理这类迭代器时,会自动拆解这三个值,每次调用next(x, 上一次的键)来获取下一组键值对。
但你的walk函数把pairs(x)的返回值直接当成单一的迭代函数传入for循环,导致Lua调用next时缺失了必需的表参数,因此触发“table expected, got nil”的报错。
修复walk函数的通用写法
要让walk同时支持两种迭代器,需要兼容Lua迭代器的标准返回格式(迭代函数、状态、初始值),修改后的代码如下:
function walk(iter, state, init) for n,i in iter, state, init do print(n, i[1]+i[#i]) end end
修改后两种调用方式都能正常工作:
- 闭包迭代器:
walk(items(x))依然有效,Lua会将闭包作为iter,state和init默认设为nil,闭包本身不依赖这两个值。 - 无状态迭代器:
walk(pairs(x))可以正常运行,pairs(x)返回的三个值会被分别对应到iter、state、init参数,符合for循环的要求。
内容的提问来源于stack exchange,提问作者Tim Menzies
相关产品推荐
相关产品推荐

