lua程序设计第二版 读书笔记(11-14章)
2013-05-11 15:14
489 查看
书本下载地址 http://download.csdn.net/detail/myy2012/5349646
本部分下载地址 http://download.csdn.net/detail/myy2012/5355935
lua程序设计第二版 读书笔记(1-4章)
第一章 开始
第二章 类型与值
第三章 表达式
第四章 语句
/article/7932654.html
lua程序设计第二版 读书笔记(5-8章)
第五章 函数
第六章 深入函数
第七章 迭代器与泛型for
第八章 编译执行与错误
/article/7932655.html
lua程序设计第二版 读书笔记(9-10章)
第九章 协同程序
第十章 完整的实例
/article/7932656.html
lua程序设计第二版 读书笔记(11-14章)
第十一章 数据结构
第十二章 数据文件与持久性
第十三章 元表metatable与元方法meatmethod
第十四章 环境
/article/7932657.html
lua程序设计第二版 读书笔记(15-17章)
第十五章 模块与包
第十六章 面向对象编程
第十七章 弱引用 table
/article/7932658.html
lua程序设计第二版 读书笔记(18-21章)
第十八章 数学库
第十九章 table库
第二十章 字符串库
第二十一章 IO库
/article/7932659.html
lua程序设计第二版 读书笔记(22-23章)
第二十二章 操作系统库
第二十三章 调试库
/article/7932660.html
11.1数组
使用整数来索引table即可在Lua中实现数组。例如:
然而,在Lua中的习惯一般是以1为数组的起始索引,Lua库和长度操作符都遵循这个预定。(如果你的数组不是从1开始的,那就无法使用这些功能了)
11.2 矩阵与多维数组
在Lua中,有2中方式来表示矩阵。
第一种:使用“数组的数组”,即一个table中的每个元素是另一个table
例如:
第二种:将2个索引合并为一个索引。
例如:
稀疏矩阵:大多数元素为0或nil。
11.3链表
由于table是动态的实体,所以在Lua中实现链表是很方便的。每个节点以一个table来表示,一个“链接”只是结点table中一个字段,该字段包含了对其他table的引用。
例如:
11.4 队列与双向队列
--------------
---------------
11.5 集合与无序组(bag)
将集合元素作为索引放入一个table中,那么对于任意值都无须搜索table,只需用该值来索引table,并查看结果是否为nil。
包,有时候也称为“多重集合”,与普通的集合不同之处在于每个元素可以出现多次。
11.6字符串缓冲
在Lua中,我们可以使用函数table.concat将一个table作为字符串缓冲,它会将给定列表中的所有字符串连接起来,并返回连接的结果。
例如
11.7图
接下来介绍一种简单的面向对象的实现:结点表示为对象、边表示为结点间的引用。
--根据给定的名称返回对应的结点
-- 构造图
-- 函数findpath采用深度优先遍历算法,在两个结点间搜索一条路径
-- 第一个参数是当前结点,第二个参数是目标节点,
-- 第三个参数用于保存从起点到当前结点的路径,第四个参数是已访问结点的集合
-- 【注意】该算法直接对结点进行操作,而不是它们的名称
-- 测试上面所列函数
将数据作为Lua代码来输出,当运行这些代码时,程序也就读取了数据。而table的构造式可以使这些输出代码看上去更像是一个普通的数据文件。
CSV(Comma-Separated Values 逗号分隔值):利用构造式作为格式。
自描述的数据(self-describing data):每项数据都伴随一个表示其含义的简短描述。
Lua不仅运行速度快,而且编译速度快。这不是偶然的结果,自从Lua创建之初就把数据描述作为Lua的主要应用之一来考虑的,开发人员能较快地编译大型程序投入了更多的努力。
12.2串行化
通常需要串行化一些数据,也就是将数据转换为一个字节流或字符流,然后就可以将其存储到一个文件中,或者通过网络连接发送出去了。串行化后的数据可以用Lua代码来表示,这样当运行这些代码时,存储的数据就可以的读取程序中得到重构了。
编写创建一个值的代码,方法如下:
可以使用一个简单且安全的方法来括住一个字符串,那就是以“%q”来使用string.format 函数。这样它就会用双引号来括住字符串,并且正确地转移其中的双引号和换行符等其他特殊字符。
例如:
Lua 5.1还提供了另一种可以以一种安全的方法来括住任意字符串的方法:[=[...]=]
--查找最长的等号序列
保存无环的table
保存有环的table
当Lua试图将两个table相加时,它会先检查两者之一是否有元表,然后检查该元表中是否有一个叫_add的字段;如果找到该字段,就调用该字段对应的值(即元方法)。
Lua中的每个值都有一个元表。Table和userdata可以有各自独立的元表,而其他类型的值则共享所属的单一元表。
标准的字符串程序库为所有的字符串都设置了一个元表
13.1算术类元表
假设使用加号(+)来计算两个集合的并集,那么需要让所有用于表示集合的table共享一个元表,并且在该元表中定义如何执行一个加法操作。
算术类元方法: 字段:__add __mul __ sub __div __unm __mod __pow (__concat)
13.2 关系类的元方法
字段:__eq(==)、 __lt(<)、 __le(<=),其他Lua自动转换 a~=b --> not(a == b) a > b --> b < a a >= b --> b <= a
例如:比较集合大小 <
与算术类的元方法不同的是,关系类的元方法不能应用于混合的类型。对于混合类型而言,关系类元方法的行为就模拟这些操作在Lua中普通的行为。如果试图将一个字符串与一个数字作顺序性比较,Lua会引发一个错误;同样,如果试图比较两个不同元方法的对象,Lua也会引发一个错误。
13.3 库定义的元方法
13.4 table访问的元方法
算术类和关系类运算符的元方法都为各种错误情况定义了行为,它们不会改变语言的常规行为。但是Lua还提供了一种可以改变table行为的方法。有两种可以改变的table行为:查询table及修改table中不存在的字段。
当访问一个table中不存在的字段时,得到的结果为nil。这是对的,但并非完全正确;实际上,这些访问会促使解释器去查找一个叫__index的元方法。如果没有这个元方法,那么访问结果如前述的为nil;否则,就由这个元方法来提供最终结果。
__index: 当访问table中不存在的字段时,得到的结果为nil。
--将Window的元方法__index指向一个匿名函数
--匿名函数的参数table和key取自于table.key。
--下面是测试代码:
说明:将一个table作为__index元方法是一种快捷、实现单一继承的方式。__index来实现相同功能的开销比较大,但方式更加灵活。
__newindex元方法:该元方法用于不存在键的赋值。当对一个table中不存在的索引赋值时,解释器就会查找__newindex元方法。如果有这个元方法,解释器就调用它,而不是执行赋值;如果这个元方法是一个table,解释器就在此table中执行赋值,而不是对原来的table。
具有默认值的table:缺省情况下,table的字段默认值为nil。但是我们可以通过元表修改这个默认值。
跟踪table的访问:__index和__newindex都是在table中没有所需访问的index时才发挥作用的。因此,为了监控某个table的访问状况,我们可以为其提供一个空table作为代理,之后再将__index和__newindex元方法重定向到原来的table上。
--输出结果为
--update of element 2 to hello
--access to element 2
--hello
只读的table:
通过代理的概念,可以很容易的实现只读table。只需跟踪所有对table的更新操作,并引发一个错误即可。
14.1具有动态名字的全局变量
正因为环境是一个常规的table,才可以使用一个key(变量名)去直接索引它。类似地,还可以动态地计算出一个名称,然后将一个值赋予具有该名称的全局变量。
例如:_G[varname] = name
14.2全局变量声明
Lua中的全局变量不需要声明就可以使用。尽管很方便,但是一旦出现笔误就会造成难以发现的错误。我们可以通过给_G表加元表的方式来保护全局变量的读取和设置,这样就能降低这种笔误问题的发生几率了。
14.3. 非全局的环境:
全局环境存在一个刚性的问题,即它的修改将影响到程序的所有部分。Lua 5为此做了一些改进,新的特征可以支持每个函数拥有自己独立的全局环境,而由该函数创建的closure函数将继承该函数的全局变量表。
本部分下载地址 http://download.csdn.net/detail/myy2012/5355935
lua程序设计第二版 读书笔记(1-4章)
第一章 开始
第二章 类型与值
第三章 表达式
第四章 语句
/article/7932654.html
lua程序设计第二版 读书笔记(5-8章)
第五章 函数
第六章 深入函数
第七章 迭代器与泛型for
第八章 编译执行与错误
/article/7932655.html
lua程序设计第二版 读书笔记(9-10章)
第九章 协同程序
第十章 完整的实例
/article/7932656.html
lua程序设计第二版 读书笔记(11-14章)
第十一章 数据结构
第十二章 数据文件与持久性
第十三章 元表metatable与元方法meatmethod
第十四章 环境
/article/7932657.html
lua程序设计第二版 读书笔记(15-17章)
第十五章 模块与包
第十六章 面向对象编程
第十七章 弱引用 table
/article/7932658.html
lua程序设计第二版 读书笔记(18-21章)
第十八章 数学库
第十九章 table库
第二十章 字符串库
第二十一章 IO库
/article/7932659.html
lua程序设计第二版 读书笔记(22-23章)
第二十二章 操作系统库
第二十三章 调试库
/article/7932660.html
第十一章 数据结构
table本身 就比数据和列表的功能强大的多,因此许多算法都可以忽略一些细节问题,从而简化它们的实现。11.1数组
使用整数来索引table即可在Lua中实现数组。例如:
a={} for i = -5, 5 do a[i]=0 end
然而,在Lua中的习惯一般是以1为数组的起始索引,Lua库和长度操作符都遵循这个预定。(如果你的数组不是从1开始的,那就无法使用这些功能了)
11.2 矩阵与多维数组
在Lua中,有2中方式来表示矩阵。
第一种:使用“数组的数组”,即一个table中的每个元素是另一个table
例如:
mt={} for i=1, N do for j=1, M do Mt[i][j] = 0 end end
第二种:将2个索引合并为一个索引。
例如:
mt={} for i=1, N do for j=1, M do Mt[(i-1)+j]=0 end end
稀疏矩阵:大多数元素为0或nil。
11.3链表
由于table是动态的实体,所以在Lua中实现链表是很方便的。每个节点以一个table来表示,一个“链接”只是结点table中一个字段,该字段包含了对其他table的引用。
例如:
list = nil list ={ next = list, value = v} local l=list <访问 l.value> l=l.next end
11.4 队列与双向队列
List={} function List.new() return {first=0, last=-1} end
--------------
function List.pushfirst(list, value) local first=list.first+1 list.first=first list[first]=value end function List.pushlast(list, value) local last=list.last-1 list.last=last list[last]=value end
---------------
function List.popfirst(list) local first=list.first if first<list.last then error("list is empty") end local value=list[first] list[first]=nil list.first=first-1 return value end function List.poplast(list) local last=list.last if list.first<last then error("list is empty") end local value=list[last] list[last]=nil list.last=last+1 return value end
11.5 集合与无序组(bag)
将集合元素作为索引放入一个table中,那么对于任意值都无须搜索table,只需用该值来索引table,并查看结果是否为nil。
包,有时候也称为“多重集合”,与普通的集合不同之处在于每个元素可以出现多次。
11.6字符串缓冲
在Lua中,我们可以使用函数table.concat将一个table作为字符串缓冲,它会将给定列表中的所有字符串连接起来,并返回连接的结果。
例如
local t={} for line in io.lines() do t[#t + 1] = line end local s = table.concat(t, “\n”)..”\n” a={"good", "girl", "bad", "boy"} local s=table.concat(a) for k, v in ipairs(a) do print(k, v) end print(s) --goodgirlbadboy
11.7图
接下来介绍一种简单的面向对象的实现:结点表示为对象、边表示为结点间的引用。
--根据给定的名称返回对应的结点
local function name2node(graph, name) if not graph[name] then graph[name]={name=name, adj={}} end return graph[name] end
-- 构造图
function readgraph() local graph={} for line in io.lines() do local namefrom, nameto = string.match(line, "(%S+)%s+(%S+)") local from = name2node(graph, nameto) -- 查找相应的结点 from.adj[to] = true -- 将“to“添加到”from“的邻接集合 end return graph end
-- 函数findpath采用深度优先遍历算法,在两个结点间搜索一条路径
-- 第一个参数是当前结点,第二个参数是目标节点,
-- 第三个参数用于保存从起点到当前结点的路径,第四个参数是已访问结点的集合
-- 【注意】该算法直接对结点进行操作,而不是它们的名称
function findpath (curr, to, path, xisited) path = path or {} visited = visited or {} if visited[curr] then --结点是否已访问过? return nil --这里没有路径 end visited[curr] = true --将结点标记为已访问 path[#path + 1] = curr --将其加到路径中 if curr == to then --最后的结点吗? return path end for node in pairs(curr.adj) do --尝试所有的邻接结点 local p = findpath(node, to, path, visited) if p then return p end end path[#path] = nil -- 从路径中删除节点 end
-- 测试上面所列函数
function printpath(path) for i=1, #path do print(path[i].name) end end g = readgraph() a = name2node(g, "a") b = name2node(g, "b") p = findpath(a,b) if p then printpath (p) end
第十二章 数据文件与持久性
12.1 数据文件将数据作为Lua代码来输出,当运行这些代码时,程序也就读取了数据。而table的构造式可以使这些输出代码看上去更像是一个普通的数据文件。
CSV(Comma-Separated Values 逗号分隔值):利用构造式作为格式。
自描述的数据(self-describing data):每项数据都伴随一个表示其含义的简短描述。
Lua不仅运行速度快,而且编译速度快。这不是偶然的结果,自从Lua创建之初就把数据描述作为Lua的主要应用之一来考虑的,开发人员能较快地编译大型程序投入了更多的努力。
12.2串行化
通常需要串行化一些数据,也就是将数据转换为一个字节流或字符流,然后就可以将其存储到一个文件中,或者通过网络连接发送出去了。串行化后的数据可以用Lua代码来表示,这样当运行这些代码时,存储的数据就可以的读取程序中得到重构了。
编写创建一个值的代码,方法如下:
function serialize(o) if type(o) == “number” then io.write(o) elseif type(o) == “string” then io.write(string.format(“%q”, o)) else <其他情况> end end
可以使用一个简单且安全的方法来括住一个字符串,那就是以“%q”来使用string.format 函数。这样它就会用双引号来括住字符串,并且正确地转移其中的双引号和换行符等其他特殊字符。
例如:
s=’a”problematic”\\string’ print(string.format(“%q”, s)) --"a\"problematic\"\\string"
Lua 5.1还提供了另一种可以以一种安全的方法来括住任意字符串的方法:[=[...]=]
--查找最长的等号序列
function quote(s) local n=-1 for w in string.gmatch(s, "]=*") do n=math.max(n, #w-1) end local eq=string.rep("=", n+1) return string.format(" [%s[\n%s]%s] ", eq, s, eq) end print(quote("good]=girl bad=boy"))
保存无环的table
保存有环的table
function basicSerialize(o) if type(o) == "number" then return tostring(o) else return string.format("%q", o) end end print(basicSerialize(45)) print(basicSerialize('three'))
第十三章 元表(metatable)与元方法(meatmethod)
可以通过元表来修改一个值的行为,使其在面对一个非预定义的操作时执行一个指定的操作。例如:a和b都是table,通过元表可以定义如何计算表达式a+b。当Lua试图将两个table相加时,它会先检查两者之一是否有元表,然后检查该元表中是否有一个叫_add的字段;如果找到该字段,就调用该字段对应的值(即元方法)。
Lua中的每个值都有一个元表。Table和userdata可以有各自独立的元表,而其他类型的值则共享所属的单一元表。
标准的字符串程序库为所有的字符串都设置了一个元表
t={} print(getmetatable(t)) --nil print(getmetatable(12)) --nil print(getmetatable("hi")) --table: 0042EB20 t1={} setmetatable(t, t1) print(getmetatable(t)) --table: 0063B378
13.1算术类元表
假设使用加号(+)来计算两个集合的并集,那么需要让所有用于表示集合的table共享一个元表,并且在该元表中定义如何执行一个加法操作。
算术类元方法: 字段:__add __mul __ sub __div __unm __mod __pow (__concat)
tA = {1, 3} tB = {5, 7} mt = {} setmetatable(tA, mt) function union(t1, t2) for _, item in ipairs(t2) do table.insert(t1, item) end return t1 end
mt.__add = union tAB = tA + tB for k, v in pairs(tAB) do print(v) --1 3 5 7 end
13.2 关系类的元方法
字段:__eq(==)、 __lt(<)、 __le(<=),其他Lua自动转换 a~=b --> not(a == b) a > b --> b < a a >= b --> b <= a
例如:比较集合大小 <
tA, tB = {3}, {1, 2} mt = {} function lessthan(tA, tB) return #tA < #tB end mt.__lt=lessthan setmetatable(tA, mt) setmetatable(tB, mt) print(tA < tB) --true
与算术类的元方法不同的是,关系类的元方法不能应用于混合的类型。对于混合类型而言,关系类元方法的行为就模拟这些操作在Lua中普通的行为。如果试图将一个字符串与一个数字作顺序性比较,Lua会引发一个错误;同样,如果试图比较两个不同元方法的对象,Lua也会引发一个错误。
13.3 库定义的元方法
13.4 table访问的元方法
算术类和关系类运算符的元方法都为各种错误情况定义了行为,它们不会改变语言的常规行为。但是Lua还提供了一种可以改变table行为的方法。有两种可以改变的table行为:查询table及修改table中不存在的字段。
当访问一个table中不存在的字段时,得到的结果为nil。这是对的,但并非完全正确;实际上,这些访问会促使解释器去查找一个叫__index的元方法。如果没有这个元方法,那么访问结果如前述的为nil;否则,就由这个元方法来提供最终结果。
__index: 当访问table中不存在的字段时,得到的结果为nil。
Window = {} Window.prototype = {x = 0, y = 0, width = 100, height = 100} Window.mt = {} --Window的元表 function Window.new(o) setmetatable(o, Window.mt) return o end
--将Window的元方法__index指向一个匿名函数
--匿名函数的参数table和key取自于table.key。
Window.mt.__index = function(table,key) return Window.prototype[key] end
--下面是测试代码:
w = Window.new{x = 10, y = 20} print(w.width) --100 print(w.height) --100 print(w.width1) --nil
说明:将一个table作为__index元方法是一种快捷、实现单一继承的方式。__index来实现相同功能的开销比较大,但方式更加灵活。
__newindex元方法:该元方法用于不存在键的赋值。当对一个table中不存在的索引赋值时,解释器就会查找__newindex元方法。如果有这个元方法,解释器就调用它,而不是执行赋值;如果这个元方法是一个table,解释器就在此table中执行赋值,而不是对原来的table。
具有默认值的table:缺省情况下,table的字段默认值为nil。但是我们可以通过元表修改这个默认值。
function setDefault(table,default) local mt = {__index = function() return default end } setmetatable(table,mt) end tab = {x = 10, y = 20} print(tab.x,tab.z) --10 nil setDefault(tab,0) print(tab.x,tab.z) --10 0
跟踪table的访问:__index和__newindex都是在table中没有所需访问的index时才发挥作用的。因此,为了监控某个table的访问状况,我们可以为其提供一个空table作为代理,之后再将__index和__newindex元方法重定向到原来的table上。
t = {} --原来的table local _t = t --保持对原有table的私有访问。 t = {} --创建代理 --创建元表 local mt = { __index = function(table,key) print("access to element " .. tostring(key)) return _t[key] --通过访问原来的表返回字段值 end, __newindex = function(table,key,value) print("update of element " .. tostring(key) .. " to " .. tostring(value)) _t[key] = value --更新原来的table end } setmetatable(t,mt)
t[2] = "hello" print(t[2])
--输出结果为
--update of element 2 to hello
--access to element 2
--hello
只读的table:
通过代理的概念,可以很容易的实现只读table。只需跟踪所有对table的更新操作,并引发一个错误即可。
第十四章 环境
环境:Lua将其所有的全局变量保存在一个常规的table(环境)中。14.1具有动态名字的全局变量
正因为环境是一个常规的table,才可以使用一个key(变量名)去直接索引它。类似地,还可以动态地计算出一个名称,然后将一个值赋予具有该名称的全局变量。
例如:_G[varname] = name
14.2全局变量声明
Lua中的全局变量不需要声明就可以使用。尽管很方便,但是一旦出现笔误就会造成难以发现的错误。我们可以通过给_G表加元表的方式来保护全局变量的读取和设置,这样就能降低这种笔误问题的发生几率了。
14.3. 非全局的环境:
全局环境存在一个刚性的问题,即它的修改将影响到程序的所有部分。Lua 5为此做了一些改进,新的特征可以支持每个函数拥有自己独立的全局环境,而由该函数创建的closure函数将继承该函数的全局变量表。
相关文章推荐
- lua程序设计第二版 读书笔记(1-4章)
- lua程序设计第二版 读书笔记(9-10章)
- lua程序设计第二版 读书笔记(15-17章)
- lua程序设计第二版 读书笔记(27-28章)
- <Lua程序设计(第二版)>书摘-11
- lua程序设计第二版 读书笔记(5-8章)
- lua程序设计第二版 读书笔记(18-21章)
- lua程序设计第二版 读书笔记(22-23章)
- <Lua程序设计(第二版)>书摘-5
- <Lua程序设计(第二版)>书摘-2
- <Lua程序设计(第二版)>书摘-8
- <Lua程序设计(第二版)>书摘-12
- <Lua程序设计(第二版)>书摘-13 日期与时间
- <Lua程序设计(第二版)>书摘-3
- <Lua程序设计(第二版)>书摘-10
- Effective Java 英文 第二版 读书笔记 Item 11:Override clone judiciously
- <Lua程序设计(第二版)>书摘-4
- <Lua程序设计(第二版)>书摘-9
- lua程序设计(第二版)(电子工业出版社黄皮)
- lua程序设计(第二版)(电子工业出版社黄皮)