迭代器与泛型 for 3
具有复杂状态的迭代器
- 使用
closure 可以保存迭代器所需保存的所有状态
- 也可以将迭代器所需的所有状态打包为一个
table 并保存在 恒定状态中
- 在循环过程中 恒定状态 总是同一个
table
- 但这个
table 的内容却可以改变即在循环过程中改变 table 数据
- 由于这种迭代器可以保存所有数据将其存储到 恒定状态中,因此第二个参数 控制变量 可以忽略
local iterator
function allwords()
local state = {line = io.read(), pos = 1}
return iterator, state
end
function iterator(state)
while state.line do -- 若为有效行的内容就进入循环
-- 搜索下一个单词
local s, e = string.find(state.line, "%w+", state.pos)
if s then -- 找到一个单词
state.pos = e + 1
return string.sub(state.line, s, e)
else -- 没有找到单词
state.line = io.read() -- 尝试读取下一行
state.pos = 1
end
end
return nil
end
错误记录
- 这里编码时犯了一个错误,没找到单词时使用的是函数定义
io.read ,而不是函数调用 io.read()
- 所以会报错
bad argument #1 to 'find' (string expected, got function)
- 意为第一个参数期望获得
string 类型,实际上得到的确实 function 类型
- 因为输入的第一行肯定会有单词,所以不会进入 else 读取下一行
- 而打印出第一行的所有单词后,就不会尝试读取输入了,因为
string.find(state.line, ...) 其中的 第一个参数已经为 function 类型了,所以循环结束
io.read() 用户输入任何东西都会为 string 类型
- 除非指定输入
io.read("*number") 这样就指定用户输入为 number 类型了
与无状态迭代器的对比
- 无状态迭代器将所有状态保存在
for 变量中
- 无需再开始一个循环时创建任何对象
- 基于
closure 实现的 table 比一个使用 table 的迭代器高效
- 因为访问 「非局部变量」要比访问
table 快
真正的迭代器
- 迭代器没有做实际的迭代,真正做迭代的是
for 循环
- 迭代器只是为每次迭代提供成功后的返回值
- 准确地称呼应为「生成器」
在迭代器中做实际的迭代操作
- 无需写循环
- 需要描述每次迭代时所需执行的动作或行为的参数,即参数为某个函数
- 迭代器接受一个函数作为参数,并在其内部循环中调用这个函数
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 语句
|