迭代器与泛型 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
错误记录git
- 这里编码时犯了一个错误,没找到单词时使用的是函数定义
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
语句
本篇文章由一文多发平台ArtiPub自动发布