更简单的 For 迭代器 |
|
当前语法如下
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 撰写)