快速掌握Lua 5.3 —— "Iterators"和"Generic for"
来源:互联网 发布:qq群发软件sudm 编辑:程序博客网 时间:2024/05/01 00:33
Q:什么是”iterator”?
A:一种允许你访问一个集合中的元素的构造。在Lua中用函数来表示”iterator”,每次调用这个函数,函数就返回集合中的下一个元素。
Q:如何创建以及使用”iterator”。
A:使用”Closure”就可以创建”iterator”。
-- 一个类似于ipairs()的iterator,但他只返回table中的value。function list_iter(t) local i = 0 return function() i = i + 1 if i <= #t then return t[i] end endendt = {10, 20, 30}-- 用"while"使用这个"iterator"。iter = list_iter(t) -- creates the iteratorwhile true do local element = iter() -- calls the iterator if element == nil then break end print(element)end-- 用"Generic for"使用这个"iterator"。for element in list_iter(t) do print(element)end
可以看出,”iterator”与”Generic for”配合的更好。省去了iter
变量保存这个”iterator”,省去了判断break
条件,省去了显式调用”iterator”。实际上”Generic for”还做了更多的事情,在之后的”Q & A”总会看到如何创建一个高效的”iterator”,其中就用到了”Generic for”额外的特性。
Q:”Generic for”的内部是如何实现的?
A:之前有提到过“Generic for”的语法,
for var1, var2, ..., var_n in exp do dosomethingend
实际上其内部做了如下的工作,
do --[[ 首先计算"in"后面的"exp"。 实际上"Generic for"允许"exp"返回三个值,他们的含义分别是: _f: "iterator function", _s: "invariant state", _var: "control variable"。]] local _f, _s, _var = exp while true do --[[ 以"invariant state"和"control variable"作为参数调用"iterator function"。 如果"iterator"还有值,则"var_1"到"var_N"都会得到值, 否则"iterator"返回"nil",即"var_1"到"var_N"都会得到"nil"]] local var_1, ... , var_n = _f(_s, _var) _var = var_1 -- "control variable"得到"var_1"的值。 --[[ 如果"control variable"得到的是"nil", 说明"iterator"中已经没有值了,那么跳出"for"循环。]] if _var == nil then break end --[[ 否则"control variable"得到的不是"nil", 说明"iterator"中还有值,那么执行"for"中给出的代码。]] dosomething -- 这个"dosomething"是上面"Generic for"循环中的那个"dosomething"。 endend
结合一个实际的例子来理解会更容易一些,
-- 用Lua实现ipairs()。function iter(a, i) -- 每次都会传递"invariant state"和"control variable"。 i = i + 1 -- 更新"control variable"。 local v = a[i] if v then --[[ 首先返回新的"control variable" (因为"Generic for"的内部实现中"control variable"接收的是"var_1"的值), 再返回其他的值。]] return i, v endendfunction ipairs(a) --[[ iter是"iterator function", a是"invariant state", 0是"control variable"的初始值。 结合上面"Generic for"的内部实现,就能明白这3个变量的意义了。]] return iter, a, 0end
Q:什么是”stateless iterator”?
A:不需要自己保存”iterator”的状态以及”control variable”,所有均由”Generic for”负责管理。
Q:什么是”complex state iterator”?
A:需要自己保存”iterator”的状态以及,并且在调用”iterator”的过程中其状态会变化。一般会使用一个”table”来保存会变化的状态(同时,一般也将”iterator”的”control variable”放入其中,所以此种模式的”iterator”一般不需要”Generic for”的”control variable”),然后将此”table”作为”invariant state”。
Q:如何创建一个高效的”iterator”?
A:首先应该尝试写一个”stateless iterator”,因为”Generic for”内部会帮助你管理”iterator”的状态,每一次调用”iterator”也没有额外的开销。如果这种模式不合适,那么就要尝试写一个”closure”,”closure”的开销比”table”的开销小,同时”closure”的访问速度也比”table”的访问速度快。如果这种模式依旧不合适,你才要考虑写一个”complex state iterator”。最后如果实在没办法了,你可以使用”coroutine”(在此不提,之后会提到)来创建”iterator”,他的功能十分强大,但是开销也不小。
“stateless iterator”的典型例子是上面用Lua实现的ipairs()。
接下来,通过一个找出输入的字符串中每一个单词的例子,展示如何创建”closure”模式以及”complex state iterator”模式的”iterator”。
--[[ "closure" mode. 每次使用时都会创建一个"closure"(自己保存"line"变量和"pos"变量)。]]function allwords () local line = io.read() -- current line local pos = 1 -- current position in the line return function () -- iterator function while line do -- repeat while there are lines local s, e = string.find(line, "%w+", pos) if s then -- found a word? pos = e + 1 -- next position is after this word return string.sub(line, s, e) -- return the word else line = io.read() -- word not found; try next line pos = 1 -- restart from first position end end return nil -- no more lines: end of traversal endend-- 用"Generic for"使用这个"iterator"。for word in allwords() do print(word)end
--[[ "complex state iterator" mode. "line"变量和"pos"变量存储在"state"这张"table"中, "state"作为"Generic for"的"invariant state"。]]function iterator (state) while state.line do -- repeat while there are lines -- search for next word local s, e = string.find(state.line, "%w+", state.pos) if s then -- found a word? -- update next position (after this word) state.pos = e + 1 return string.sub(state.line, s, e) else -- word not found state.line = io.read() -- try next line... state.pos = 1 -- ... from first position end end return nil -- no more lines: end loopendfunction allwords () local state = {line = io.read(), pos = 1} return iterator, stateend-- 用"Generic for"使用这个"iterator"。for word in allwords() do print(word)end
附加:
1、在连续调用”iterator”的过程中,”iterator”需要保存一个“状态”,通过这个“状态””iterator”才能知道如何获取下一个元素,“Closures”能很好的完成这个任务(“Closures”是一个能够访问包含他的函数中的局部变量的函数)。
- 快速掌握Lua 5.3 —— "Iterators"和"Generic for"
- LUA学习笔记2-Iterators and the Generic for
- 快速掌握Lua 5.3 —— 各种变量和值
- 快速掌握Lua 5.3 —— 函数
- 快速掌握Lua 5.3 —— Coroutines
- 快速掌握Lua 5.3 —— 数据结构
- 快速掌握Lua 5.3 —— 环境
- 快速掌握Lua 5.3 —— packages
- 快速掌握Lua 5.3 —— 资源管理
- Chapter 7Iterators and the Generic for
- 快速掌握Lua 5.3 —— 让我们开始吧
- 快速掌握Lua 5.3 —— 编译,运行以及错误
- 快速掌握Lua 5.3 —— 两个完整的例子
- 快速掌握Lua 5.3 —— 数据操作
- 快速掌握Lua 5.3 —— "metatables" and "metamethods" (1)
- 快速掌握Lua 5.3 —— "metatables" and "metamethods" (2)
- 快速掌握Lua 5.3 —— 面向对象编程
- 快速掌握Lua 5.3 —— "table"库
- ExpandableListView安卓开发可扩展的listview
- 堆排序算法
- JavaScript 学习摘要
- Jquery scroll 向下滚动到据顶部超过1000px时,回到顶部
- Python的Module和Package
- 快速掌握Lua 5.3 —— "Iterators"和"Generic for"
- 浏览器引擎
- oracle查询一个时间段每天的数据量
- python数字图像处理(2):图像的读取、显示与保存
- 静态链表类模板的实现
- Java WebService查看请求报文
- Android中LocalSocket使用
- 菜鸟在线技术篇之数据类型及转换
- ubuntu15.10中文输入法问题