具有复杂状态的迭代器: 通常,迭代器需要许多状态,但是在泛型for中只提供三种值的保存,其中是两个是用于状态的保存:①恒定状态,②控制变量
;
所以当我们想要使用迭代器保存更多状态时我们可以使用closure
或者使用一个table
来进行打包;使用table实现的具有复杂状态的迭代器就可以通过这个table保存任意多的数据了,并且它还可以在循环过程中改变这些数据;
下面是一个实现读取文件中每一行单词的具有复杂状态的迭代器
--打开文件往里面写入数据
file = io.open("./text.txt","w+")
file:write("Can you can a can as a canner can can a can\n这是新的一行\ncan you love me?\n")
file:close()
--打开文件,用于迭代读取文件中的数据
file = io.open("./text.txt","r")
function iter( state )--迭代器函数
while state.line do
local s,e = string.find(state.line,"%w+",state.pos) --在每一行中查找一个单词
if s then --如果返回值不为nil
state.pos = e + 1
return string.sub(state.line,s,e) --返回查找到的单词
else --如果一行中没有找到单词就读取下一行
state.line = file:read()
state.pos = 1
end
end
return nil
end
function allworld( )
local state = {line = file:read(),pos = 1}
return iter ,state
end
for k in allworld() do
print(k)
end
file:close()
在上面代码示例中,使用了一个state
的table用于保存多个状态,其中保存了一个每一行数据的字段line以及读取到当前行什么位置的字段pos;迭代的起始函数比较简单只需返回迭代器函数及初始状态
一般尽可能地尝试编写无状态得迭代器,那些迭代器会将将状态保存到for变量中;不需要在开始一个循环时创建任何新的对象;如果迭代器无法套用这个模型,那么就应该尝试使用closure。closure显得更加优雅并且一个基于closure实现的迭代器会比一个使用table的迭代器更为高效。这是因为,首先创建一个closure会比创建一个table更廉价,其次访问"非局部变量"也比访问table字段更快。
当然使用协同程序(coroutine)编写的迭代器才是功能最强的,但稍微会有一点开销