The for statement has two forms: one numeric and one generic.
The numeric for loop repeats a block of code while a control variable runs through an arithmetic progression. It has the following syntax:
stat ::= for Name `=´ exp `,´ exp [`,´ exp] do block end The block is repeated for name starting at the value of the first exp, until it passes the second exp by steps of the third exp. More precisely, a for statement like
for v = e1, e2, e3 do block end is equivalent to the code:
do local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3) if not (var and limit and step) then error() end while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do local v = var block var = var + step end end Note the following:
All three control expressions are evaluated only once, before the loop starts. They must all result in numbers. var, limit, and step are invisible variables. The names shown here are for explanatory purposes only. If the third expression (the step) is absent, then a step of 1 is used. You can use break to exit a for loop. The loop variable v is local to the loop; you cannot use its value after the for ends or is broken. If you need this value, assign it to another variable before breaking or exiting the loop. The generic for statement works over functions, called iterators. On each iteration, the iterator function is called to produce a new value, stopping when this new value is nil. The generic for loop has the following syntax:
stat ::= for namelist in explist do block end namelist ::= Name {`,´ Name} A for statement like
for var_1, ···, var_n in explist do block end is equivalent to the code:
do local f, s, var = explist while true do local var_1, ···, var_n = f(s, var) var = var_1 if var == nil then break end block end end Note the following:
explist is evaluated only once. Its results are an iterator function, a state, and an initial value for the first iterator variable. f, s, and var are invisible variables. The names are here for explanatory purposes only. You can use break to exit a for loop. The loop variables var_i are local to the loop; you cannot use their values after the for ends. If you need these values, then assign them to other variables before breaking or exiting the loop.
可以得出结论:
for有两种格式
数字类型
泛型
泛型依靠迭代函数
数字类型的其实和其他语言没啥区别,我们要看的是泛型的迭代器
LUA的泛型For迭代器
泛型 for 在自己内部保存迭代函数,实际上它保存三个值:迭代函数、状态常量、控制变量。 泛型 for 迭代器提供了集合的 key/value 对,语法格式如下:
1 2 3
for k, v in pairs(t) do print(k, v) end
执行过程:
首先,初始化,计算in后面表达式的值,表达式应该返回泛型 for 需要的三个值:迭代函数、状态常量、控制变量;与多值赋值一样,如果表达式返回的结果个数不足三个会自动用nil补足,多出部分会被忽略。
状态常量通过常量字眼我们就知道了它是不变的最终条件,而控制变量其实就是我们迭代器需要的第一个初值 iterator functions .Its results are an iterator function, a state, and an initial value for the first iterator variable.
k, v 就是我们for迭代器每次迭代返回的值
无状态迭代器 和 有状态迭代器
无状态的迭代器是指不保留任何状态的迭代器,因此在循环中我们可以利用无状态迭代器避免创建闭包花费额外的代价。 每一次迭代,迭代函数都是用两个变量(状态常量和控制变量)的值作为参数被调用,一个无状态的迭代器只利用这两个值可以获取下一个元素。 这种无状态迭代器的典型的简单的例子是ipairs,它遍历数组的每一个元素。 以下实例我们使用了一个简单的函数来实现迭代器,实现 数字 n 的平方:
1 2 3 4 5 6 7 8 9 10 11 12
function square(iteratorMaxCount,currentNumber) if currentNumber<iteratorMaxCount then currentNumber = currentNumber+1 return currentNumber, currentNumber*currentNumber end end
function elementIterator (collection) local index = 0 local count = #collection -- 闭包函数 return function () index = index + 1 if index <= count then -- 返回迭代器的当前元素 return collection[index] end end end
for element in elementIterator(array) do print(element) end
function aaa(x) local a = x; function ccc(y) print(y) end return ccc,a end for v in aaa(123) do end
分析:这里其实就是自己定义了一个迭代器
for in 可以看出是迭代器
表达式aaa(123) 返回了一个匿名函数作为得到函数ccc 和一个状态常量 a
就像手册里说的
1 2 3 4 5 6 7 8 9
do local f, s, var = explist //这里是表达式的result 迭代函数f 状态常量s 控制量var while true do local var_1, ···, var_n = f(s, var) var = var_1 if var == nil then break end block end end
每次迭代,我们这里其实就是执行了一个print而已
下面我们看一个通常的使用方式GOOD
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
local function itor(self, current) if current.next and self._header ~= current.next then return current.next, current.next.target end end function xxx:__pairs() return itor, self, self._header end --usage for node, anim in pairs(list) do local anim_state = anim.state if anim_state == STATE_READY then anim:play() end end