Lua学习笔记09:复杂状态的迭代器(迭代器与泛型for-03)

一、具有复杂状态的迭代器:迭代器需要保存许多状态,可是泛型(for)却只提供了恒定状态和控制变量用于状态的保存。一个最简单的办法是使用closure。当然我们还以将所有的信息封装到一个table中,并作为恒定状态对象传递给迭代器。虽说恒定状态变量本身是恒定的,即在迭代过程中不会换成其它对象,但是该对象所包含的数据是否变化则完全取决于迭代器的实现。就目前而言,由于table类型的恒定对象已经包含了所有迭代器依赖的信息,那么迭代器就完全可以忽略泛型(for)提供的第二个参数。
解决方法:使用 closure 可以保存迭代器所需保存的所有状态;也可以将迭代器所需的所有状态打包为一个 table 并保存在 恒定状态中;在循环过程中 恒定状态 总是同一个 table,但这个 table 的内容却可以改变即在循环过程中改变 table 数据;由于这种迭代器可以保存所有数据将其存储到 恒定状态中,因此第二个参数 控制变量 可以忽略
例:
local iterator
function allwords()
     local state { line = io.read(), pos = 1 }
     return iterator, state
 end
 --iterator函数将是真正的迭代器
function iterator(state)
     while state.line do    --若为有效行内容就进入循环
         local s,e = string.find(state.line,"%w+",state.pos)    --搜索下一个单词
         if s then   --如果找到一个单词
             state.pos = e + 1   --将pos定义为下一个单词的起始位置
             return string.sub(state.line,s,e)   --返回该单词
         else  --没有找到单词
             state.line = io.read()  --尝试下一行
             state.pos = 1  --从下一行的第一个位置开始找是否有单词
         end
     end
     return nil
end

与无状态迭代器的对比:
无状态迭代器将所有状态保存在 for 变量中
无需再开始一个循环时创建任何对象
基于 closure 实现的 table 比一个使用 table 的迭代器高效,因为访问 「非局部变量」要比访问 table快
可以在循环的过程中改变数据,尽管循环时恒定状态table相同,但是table的内容是可以改变的
1、应尽可能的编写无状态迭代器,这样迭代器可以将所有的状态保存在for的变量中,不需要在开始一个循环的时候创建一个新的对象
2、若一个迭代器无法套用上面例子中的方法时,应该使用closure,这样代码会好用好看些,通常用一个closure实现的迭代器会比用一个table实现的迭代器更加高效

二、真正的迭代器:迭代器没有做实际的迭代,真正做迭代的是 for 循环;迭代器只是为每次迭代提供成功后的返回值;准确地称呼应为「生成器」
1、如果在迭代器中做实际的迭代操作:无需写循环;需要描述每次迭代时所需执行的动作或行为的参数,即参数为某个函数,以这个参数来调用迭代器;迭代器接受一个函数作为参数,并在其内部循环中调用这个函数
例:
function allwords(f)
    for line in io.read() do
        -- gmatch 匹配所有符合模式的字符串
        for word in string.gmatch(line, "%w+") do
            f(word)
        end
    end
end
allwords(print)
--------------------------------
local count = 0
allwords(function(w)
    if w == "hello" then
        count = count + 1
    end
end  --也可以使用匿名函数作为参数
)
print(count)
--------------------------------------
local count = 0
for w in allwords() do
    if w == "hello" then
        count = count + 1
    end
end
print(count)
--用生成器的风格实现以上例子的功能
-------------------------------------
迭代器与生成器的对比
相同点:
开销一致,每次迭代都有一次函数调用
不同点:
迭代器
return 语句只能从匿名函数中返回,不能从做迭代的函数中返回,编写容易
生成器
编写方式较为灵活,生成器允许两个或多个并行的迭代过程,逐个单词的比对两个文件,需同时遍历两个文件,且可在迭代体中使用 break 和 return 语句

你可能感兴趣的:(Lua学习笔记)