Simpler For Iterator |
|
当前的语法如下:
for A, data in iterator_func, X, Y do block end
Data 是函数返回的实际数据,之后在块中使用。A、X 和 Y 的含义将在下面进一步解释。这里是基于教程示例实现的集合迭代器和生成器迭代器的可能实现(力求明确,并从 1 开始以作改变)
-- collection iterator -- numbers = {1,3,5,7,9,11,13} function coll_squares(coll) local function next_square(coll, index) if index > #coll then return nil end n = coll[index] return index+1, n*n end return next_square, coll, 1 end for i, square in coll_squares(numbers) do print (square) end --> OK -- generator iterator -- function gen_squares(limit) local function next_square(limit, number) if number > limit then return nil end return number+1, number*number end return next_square, limit, 1 end for n, square in gen_squares(7) do print (square) end --> OK
那么,A、X 和 Y 是什么?对于集合
很难找到一个共同点来有意义地解释和命名 A、X 和 Y。X 在参考手册中称为“s”,在教程中称为“state”。在参考手册中,A 称为 var1,而 Y 称为 var。这里有一个尝试来理解它们:
上面的代码可以重写如下:
-- collection iterator -- function coll_squares(coll) local index = 1 local coll = coll -- just to make things clear local function next_square() if index > #coll then return nil end n = coll[index] index = index+1 return n*n end return next_square end for square in coll_squares(numbers) do print (square) end -- OK -- generator iterator -- function gen_squares(limit) local number = 1 local limit = limit -- ditto local function next_square() if number > limit then return nil end n = number number = number+1 return n*n end return next_square end for square in gen_squares(7) do print (square) end -- OK
存在一些细微的差异,除了最后一点,其他都是简化。
我们可以想象更复杂的情况,例如指定生成器间隔。附加数据成为迭代器参数。
-- generator iterator -- function gen_squares(start, stop, step) local number = start local function next_square() if number > stop then return nil end n = number number = number+step return n*n end return next_square end for square in gen_squares(3,9,2) do print (square) end --> OK
同理,如果我们复杂化一个集合迭代器(这里是人为地):
-- collection iterator -- require "math" numbers = {1,3,5,7,9,11,13,15,17} function coll_squares(coll, modulo) local index = 1 local function number_filter() -- return next number in coll multiple of modulo, else nil while (index < #coll) do number = coll[index] if math.fmod(number, modulo) == 0 then return number end index = index+1 end return nil end local function next_square() -- yield squares of multiples of modulo in coll n = number_filter() if not n then return nil end index = index+1 return n*n end return next_square end for square in coll_squares(numbers, 3) do print (square) end --> OK
在所有情况下,A、X 和 Y 似乎都是不必要的。这种实现迭代器的方式充分利用了 Lua 的基本特性:函数作为值、嵌套函数、闭包/上值。因此,问题是:通过去掉 A、X 和 Y,我们能否简化“for”语法、迭代器和迭代器函数之间的接口?如果可以,新的语法可能是:
for data in iterator_func do block end
for A, data in iterator_func, X, Y do block end
因此,迭代器的多样性将不会被语法本身以一种相当复杂的方式全局捕获,而是留给用户来实现。(请纠正,如果有错误,包括术语)学习和解释语法以及为特定任务编写迭代器的正确方法肯定会更容易。
参考手册指出:
(第一页表述由 DeniSpir)