《lua程序设计》读书笔记 第七章:迭代器与泛型for
来源:互联网 发布:宁波软件外包 编辑:程序博客网 时间:2024/06/13 01:31
7.1 迭代器与closure
“迭代器”就是一种遍历一种集合中所有元素的机制,在Lua中,通常将迭代器表示为函数,没调用一次函数,便返回集合中的“下一个”元素。closure为迭代器提供了绝佳的支持,一个closure结构通常涉及到两个函数:closure本身和一个用于创建closure的工厂函数。
我们编写一个简单的迭代器,返回table中每个元素的值:
function value(t) local i = 0 return function() i = i + 1; return t[i] end end
在本例中,value是一个工厂,它将返回一个闭包closure。使用该迭代器遍历一个table如下:
t = {10, 20, 30}iter = value(t)while true do local element = iter() if element == nil then break end print(element)end
然而使用泛型for则更为简单,它正是为迭代器而设计的:
t = {10, 20, 30}for val in value(t) do print(val)end
再看一个稍微复杂点的示例:
function allwords() local line = io.read() local pos = 1 return function() while line do local s,e = string.find(line, "%w+", pos) if s then pos = e + 1 return string.sub(line, s, e) else line = io.read() pos = 1 end end return nil endendfor word in allwords() do print(word)end
7.2 泛型for的语义
前面提到的迭代器都有一个缺点,就是需要为每个新的循环都创建一个closure。
泛型for在循环过程内部保存了迭代器函数,实际上它保存了3个值:一个迭代器函数、一个恒定状态和一个控制变量。泛型for语法如下:
for <var-list> in <exp-list> do < body >end
< var-list > 是一个或多个变量名的列表,以逗号分隔;< exp-list > 是一个或多个表达式的列表,同样以逗号分隔。通常表达式列表只有一条语句,即对迭代器工厂的调用。变量列表的第一元素为“控制变量”。在循环过程中该值绝不会为nil,因为当它为nil时循环就结束了。
for做的第一件事情是对in后面的表达式求值。这些表达式应该返回3个值供for保存:迭代器函数、恒定状态、控制变量的初值。这里有点类似多重赋值,即只有最后的表达式才会产生多个结果,且最多保留3个值。
明确的说,以下语句:for var_1, …, val_n in < explist > do < block > end
等价于以下代码:
do local _f, _s, _var = < explist > while true do local var_1, ... var_n = _f(s, _var) _var = var_1 if _var = nil then break end <block> endend
当我们使用一个简单的迭代器时,工厂只返回一个迭代器函数,因此恒定状态和控制变量就是nil了。
7.3 无状态的迭代器
所谓无状态的迭代器,就是自身不保留任何状态的迭代器,在每次迭代时,for循环会用恒定状态和控制变量来调用迭代器函数来生成下一个元素。典型例子就是ipairs。
自己实现ipairs如下:
local function iter(a, i) i = i + 1 local v = a[i] if v then return i, v endendfunction ipairs(a) return iter, a, 0end
7.4 具有复杂状态的迭代器
同行迭代器需要保存很多状态,可是for循环只提供了一个恒定状态和一个控制变量。一个简单的解决方法就是使用closure,或者还可以将迭代器所需的所有状态打包为一个table,保存在恒定状态中。
local iteratorfunction allwords() local state = {line = io.read(), pos = 1} return iterator, stateendfunction 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 nilend
尽可能编写无状态的迭代器,那样所有状态保存在for变量中,不需要在开始一个循环时创建新的对象。否则,应该尝试使用closure,因为通常一个closure的实现的迭代器比一个使用table的迭代器更加高效,这是因为一个closure比一个table更廉价,其次访问“非局部的变量”比访问table字段更快。
7.5 真正的迭代器
实际上上述所说的迭代器并没有做实际的迭代,真正做迭代的是for循环。而迭代器只是为每次迭代提供一些成功后的返回值,其更像是一个“生成器”。还有一种创建迭代器的方式是,在迭代器中做实际的迭代操作:
function allwords(f) for line in io.lines() do for word in string.gmatch(line, "%W+") do f(word) end endend
两种迭代器有大致相同的开销,但是生成器风格的迭代器更加灵活。
- 《lua程序设计》读书笔记 第七章:迭代器与泛型for
- Lua学习笔记 第七章 迭代器与泛型for
- Lua程序设计第二版(笔记) 第七章迭代器与泛型for
- lua语言-《lua程序设计》6~7章函数和迭代器与泛型for
- Lua程序设计笔记之三: 迭代器与泛型for
- 《lua程序设计》读书笔记 第二章:类型与值
- 《lua程序设计》读书笔记 第8章:编译、执行与错误
- 第七课 迭代器与泛型for
- lua中的迭代器与泛型for
- Lua迭代器与泛型for
- Lua中的迭代器与泛型for
- Lua中的迭代器与泛型for
- Lua 迭代器与泛型for
- JS高级程序设计读书笔记(第七章)
- 《lua程序设计》读书笔记 第三章:表达式
- 《lua程序设计》读书笔记 第四章:语句
- 《lua程序设计》读书笔记 第五章:函数
- 《lua程序设计》读书笔记 第六章:深入函数
- Tensorflow Device 和 DeviceContext
- [RK3288][Android6.0] Audio中的录音重采样小结
- XTTS 简介
- java多线程---读写锁的应用
- 动态规划解决数字塔-数字三角形问题
- 《lua程序设计》读书笔记 第七章:迭代器与泛型for
- MySQL 乐观锁与悲观锁
- JSP 使用smartupload上传文件,JSP+servlet
- 程序员常用远程工具有哪些?
- httpparse linux 截包工具
- Object类中的wait()方法和notify()方法
- git 指令易忘记部分
- 镜像图片文件制作
- sharepoint打开网页时,修正发生意外错误页面,错误日志ID查询方法