木骰

泛型for

泛型for通过对迭代器的调用来遍历一个集合的所有元素,它在循环过程内部实际上保存了一个迭代器函数,一个恒定状态和一个控制变量

泛型for的语法:

for <var-list> in <exp - list > do
<body>
end

其中 < var - list >是变量列表,以逗号分隔;< exp - list >是表达式的列表,也以逗号分隔。一般这个地方就是对一个迭代器函数的调用。例如:

for k,v in pairs(t) do print(k,v) end

k,v即为变量列表, pairs(t)即为表达式列表
变量列表里的值都是由for对于迭代器函数的执行调用而得的。而变量列表里的第一个变量就是 控制变量 ,当控制变量的值为nil 也即 对迭代器函数的一次调用返回了nil ,则标志着迭代器函数对集合的遍历已经结束,for循环也就到此结束了。

for做的第一件事就是对 in ( for … in … do )后面的表达式求值。这些表达式应该返回3个值供for保存:迭代器函数,恒定状态和控制变量的初值。

这里控制变量就是变量列表中的第一个变量即k,
迭代器函数注意可不是pairs(),pairs()将会返回一个迭代器函数 供for保存,在之后的循环中 for 将会调用这个迭代器函数来对变量列表进行赋值。(实际上这里的pairs将会返回的迭代器函数应该是next,一个内置的用于遍历table元素的迭代器)这里pairs除了返回这个next迭代器还应该返回一个控制变量的初值和一个恒定状态(依照泛型for的语法定义来说),在之后的循环中,for将会以控制变量和这个恒定状态作为参数来调用next迭代器。
恒定状态则往往是一个迭代器函数的遍历对象,一个集合,上面的示例中就是 t,一个table。

for在之后的循环中将会以恒定状态和控制变量来调用迭代器函数,再将迭代器函数的返回值赋给变量列表中的变量,若第一个返回值(即控制变量的值)为nil,则循环终止,否则for将会执行它的循环体,并重复这个过程。
对于一般的泛型for语法:

for var1,...,var_n in < explist > do < block > end

则应当等价于下面的代码:

do
local _f,_s,_var = < explist >
--此处为for对表达式列表的第一次求值,获得迭代器_f,恒定状态_s和控制变量_var
while true do
local var_1,...,var_n = _f(_s,_var)
--将第一个返回值赋还给控制变量 以便下一次循环
_var = _var1
if _var ==
nil then break end
<block>--自定义代码块
end
end

无状态的迭代器

所谓“无状态的迭代器”,正如起名所暗示的那样,就是一种自身不保存任何状态的迭代器(这是由于一般迭代器都会伴随着闭包,保存迭代过程的状态)

由于泛型for会保存恒定状态和控制变量这一特性,无状态迭代器就是依靠这一特性,把本需要开闭包来保存的迭代状态丢给了for来保存。ipairs()就是一个典型的无状态迭代器,用来遍历一个数组,for将会为它保存恒定状态–遍历的对象数组,控制变量–下标。
需要主意的是 这里的ipairs()也不是一个迭代器,它将会返回一个迭代器函数。
ipairs的的lua实现大概是这样的:

local function iter(a, i)
i = i + 1
local v = a[i]
if v then
return i,v
end
end
--ipairs返回迭代器函数iter,恒定状态a和控制变量的初值0
function ipairs( a )
return iter,a,0
end

pairs与ipairs类似,也用于遍历table,但是pairs的迭代器函数是lua内置的next函数。
next函数带有两个参数,用于遍历的table,和一个索引k
每次调用next(t, k) 时 将会以table中的任意次序返回一组值:下一个索引k和当前索引k对应的值v。当调用next( t, nil )时将会返回t的第一组值。当没有下一组值时 next则直接返回一个nil。注意这个nil将会被赋值给for变量列表的第一个变量 控制变量,则这个时候for将会终止。

有些人不喜欢用pairs,而是直接在for里用next

for k,v in next,t do
< body >
end

像这样的写法也没问题。 next, t共同组成一个表达式列表,for会自动将表达式列表的返回值调整为3个,此处这样的写法 表达式列表将会返回next, t, nil正好与pairs的返回一致。

for对表达式列表的第一次求值,next, t 的写法为赋值写法等价于

_f,_s,_var = next,t
--此处赋值变量不足3个,则自动以nil补齐

而若为pairs(t)的写法 则等价于

_f,_s,_var = pairs(t)
--由pairs返回3个值
for会自动调整表达式列表的返回值为3个

for将自动调整表达式的值为3个,所以如果有多个表达式,并返回多个值,那么也将只取前三个保存

for k,v in pairs(t),ipairs(t) do
end
--对于这样的写法 实际上只是在以pairs遍历 因为ipairs 的返回值将被丢弃
_f,_s,_var = pairs(t),ipairs(t)
— 于 共写了2114个字
— 文内使用到的标签:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*