无状态迭代器:即在使用迭代器时其本身不会保存任何状态
的值或者变量
但是其实在每次迭代中,for循环也依旧会保存着三个变量:迭代器函数、恒定状态和控制变量;但是就不会像closure闭包函数一样会拥有着一个“非局部变量(upvalue)”
,这个"非局部变量"
就是迭代器的一个状态值;因此无状态迭代器其实就可以节省了创建closure的开销了(实际就是创建upvalue的开销);最典型的无状态迭代器例子就是ipairs函数,ipairs函数可用于迭代一个数组的所有元素;因此我们可以自行实现一个类似地函数,如下所示:
-- 无状态迭代器函数
function iter( t,i )
i = i + 1
if t[i] then
return i,t[i]
end
end
function ipair( t ) --迭代器
return iter,t,0
end
tb = {1,2,3,4}
for k,v in ipair(tb) do
print(k,v)
end
在上述代码中,当for循环调用ipair函数后将会获得三个值(即ipair的三个返回值),分别为:
①迭代器函数iter
②恒定状态t
③控制变量0
同时由于无状态迭代器不会像closure函数一样保存着一些状态,因此我们就可以在多个循环中使用同一个无状态的迭代器,例如下面这样重复使用同一个无状态迭代器是没问题的
function iter( t,i )
i = i + 1
if t[i] then
return i,t[i]
end
end
function ipair( t )
return iter,t,0
end
tb = {1,2,3,4}
for k,v in ipair(tb) do
print(k,v)
end
print("============分割线===============")
--调用同一个迭代器函数ipair
tb1 = {4,3,2,1} --并
for k,v in ipair(tb1) do
print(k,v)
end
无状态迭代器还有一个有趣的例子,就是使用无状态迭代器来对链表进行遍历,它的好处就是在遍历链表过程中节省了很多创建upvalue的开销
list = nil
for i=0,10 do --创建十个节点
list = {value=i,next=list}
end
function iter( l,node ) --无状态迭代器函数
if not node then
return l
else
return node.next
end
end
function getValue( list ) --迭代器
return iter ,list ,nil
end
for node in getValue(list) do
print(node.value)
end
在这个遍历链表的无状态迭代器中,通过将list头节点作为恒定状态,并使用nil作为它的控制常量;第一次时就会返回头节点,这样下一次调用时控制变量就变成了node就等于list了;这个时候才能正常去遍历链表的数据了