快速掌握Lua 5.3 —— "Iterators"和"Generic for"
2016-01-16 02:56
381 查看
Q:什么是”iterator”?
A:一种允许你访问一个集合中的元素的构造。在Lua中用函数来表示”iterator”,每次调用这个函数,函数就返回集合中的下一个元素。Q:如何创建以及使用”iterator”。
A:使用”Closure”就可以创建”iterator”。[code]-- 一个类似于ipairs()的iterator,但他只返回table中的value。 function list_iter(t) local i = 0 return function() i = i + 1 if i <= #t then return t[i] end end end t = {10, 20, 30} -- 用"while"使用这个"iterator"。 iter = list_iter(t) -- creates the iterator while 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”的语法,[code]for var1, var2, ..., var_n in exp do dosomething end
实际上其内部做了如下的工作,
[code]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"。 end end
结合一个实际的例子来理解会更容易一些,
[code]-- 用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 end end function ipairs(a) --[[ iter是"iterator function", a是"invariant state", 0是"control variable"的初始值。 结合上面"Generic for"的内部实现,就能明白这3个变量的意义了。]] return iter, a, 0 end
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”。
[code]--[[ "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 end end -- 用"Generic for"使用这个"iterator"。 for word in allwords() do print(word) end
[code]--[[ "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 loop end function allwords () local state = {line = io.read(), pos = 1} return iterator, state end -- 用"Generic for"使用这个"iterator"。 for word in allwords() do print(word) end
附加:
1、在连续调用”iterator”的过程中,”iterator”需要保存一个“状态”,通过这个“状态””iterator”才能知道如何获取下一个元素,“Closures”能很好的完成这个任务(“Closures”是一个能够访问包含他的函数中的局部变量的函数)。相关文章推荐
- 快速掌握Lua 5.3 —— 函数
- Lua中的table函数库
- lua和c的亲密接触
- sicily 递归练习 1005. Arithmetic Expression Evaluation
- lua和c的亲密接触
- lua BaseClass
- lua 怎么写两个字符串相加
- (java)Evaluate Reverse Polish Notation
- LUA解析json小demo
- LUA解析json小demo
- windows下编译LUA-cjson
- windows下编译LUA-cjson
- lua c closure的使用
- lua 绑定c++
- liunx 下 C/C++调用luajit
- 用lua写Android界面学习笔记
- [转载]轻量级Lua IDE ZeroBrane Studio 的使用技巧和汉化
- 从零开始——Windows环境lua编程
- leetcode--Evaluate Reverse Polish Notation
- Lua 表达式