上一篇: Lua基础学习(三)https://blog.youkuaiyun.com/sun_zeliang/article/details/86677031
Lua元表
元表的作用
在Lua中,每个值通常都有一套预定义的操作集合,例如数字的相加,字符串的连接。而table比较特殊,没有办法直接将两个table相加,没有办法对函数作比较,也没有办法调用一个字符串,这个时候就需要元表来完成。
元表的方法
元表中有两个重要的方法:
setmetatable(table,metatable) 对指定 table 设置元表(metatable),如果元表(metatable)中存在 __metatable 键值,setmetatable 会失败。
getmetatable(table) 返回对象的元表(metatable)。
示例:
mytable1={}
mytable2={}
mymetatable={}
setmetatable(mytable2,mymetatable)
print("mytable1的元表为:",getmetatable(mytable1))
print("mytable2的元表为:",getmetatable(mytable2))
print("hi的元表为:",getmetatable("hi"))
print("10的元表为:",getmetatable(10))
输出:
通过观察输出发现, mytable1没有设置元表,mytable2设置了元表,在默认情况下,lua里面的字符串是有元表的,其他类型的值都没有,还有在lua代码中,只能设置table的元表,如果要设置其他类型的值的元表,必须通过C代码。
元表的使用
__add | 对应的运算符 '+'. |
__sub | 对应的运算符 '-'. |
__mul | 对应的运算符 '*'. |
__div | 对应的运算符 '/'. |
__mod | 对应的运算符 '%'. |
__unm | 对应的运算符 '-'. |
__concat | 对应的运算符 '..'. |
__eq | 对应的运算符 '=='. |
__lt | 对应的运算符 '<'. |
__le | 对应的运算符 '<='. |
Set = {}
Set.mt = {} --共享元表
function Set.new(l) --根据参数列表中的值创建一个新的集合
local set = {}
setmetatable(set,Set.mt)
for _, v in ipairs(l) do set[v] = true end --把集合中的每个值都作为set的索引
return set
end
function Set.union(a,b) --并集
local res = Set.new{}
for i in pairs(a) do res[i] = true end
for i in pairs(b) do res[i] = true end
return res
end
function Set.intersection(a,b) --交集
local res = Set.new{}
for i in pairs(a) do res[i] = b[i] end
return res
end
function Set.tostring(set)
local s="{"
local sep=""
for i in pairs(set) do
s = s..sep..i
sep=","
end
return s.."}"
end
function Set.print(set)
print(Set.tostring(set))
end
Set.mt.__add=Set.union
s1 = Set.new{6,2}
s2 = Set.new{2,4}
s3 = s1 + s2
Set.print(s3)
Set.mt.__mul=Set.intersection
s4 = s1*s2
Set.print(s4)
__index元方法:
当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的__index 键。如果__index包含一个表格,Lua会在表格中查找相应的键。
感觉有点像C#的访问器get,只是__index可以追踪查找。
示例:
Window = {} --创建一个名字空间
Window.prototype = {x=0,y=0,width=50,height=100}
Window.mt = {} --创建元表
function Window.new(o) --声明一个构造函数
setmetatable(o,Window.mt)
return o
end
Window.mt.__index = function(table,key) --定义__index元方法
return Window.prototype[key]
end
w = Window.new{x=10,y=20}
print(w.width)
print(w.w)
输出:
在Lua中,如果检测到w中没有width字段,但是在元表中有__index字段,那么Lua就会以 w 和 width 来调用__index元方法,然后返回结果。
__index元方法不必一定是一个函数,也可以是一个table,上面__index的声明就可以改写成:
Window.mt.__index = Window.prototype
这种写法更便捷,且更直观,如果在w 中没有找到,就会到Window.prototype 里继续查找,类似于访问 Window.prototype["windth"]。
将函数作为__index元方法的优势在于灵活,但是相较于table 会有更大的开销。
__newindex元方法:
和前面的__index 元方法类似,区别在于__index 是访问,而__newindex 是修改。
只读的table,示例:
function ReadOnly(t)
local p = {}
local mt = {
__index = t,
__newindex = function(t,k,v)
error("attempy to update a read-only table",2)
end
}
setmetatable(p,mt)
return p
end
days = ReadOnly{"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}
print(days[1])
days[2] = "Noday"
print(days[3])
输出:
Lua协同程序
线程和协同程序区别
线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。
在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。
协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。
协同程序操作
coroutine.create() 创建一个协同程序
coroutine.resume() 启动或再次启动一个暂停的协同程序
coroutine.status() 返回的是协同程序的状态
coroutine.yield() 挂起一个协同程序
coroutine.wrap() 和create类似,也是创建协同程序,但是warp返回的不是协同程序本身,返回的是一个函数
示例:
co = coroutine.create(function() print("hi") end) --创建一个协同程序
print(co)
print(coroutine.status(co)) --打印协同程序co的状态
coroutine.resume(co) --启动或再次启动一个暂停的协同程序
print(coroutine.status(co))
co = coroutine.create(function()
for i=1,5 do
print("co",i)
coroutine.yield() --将协同程序挂起
end
end)
coroutine.resume(co) --输出 1 后被挂起
coroutine.resume(co)
coroutine.resume(co)
coroutine.resume(co)
coroutine.resume(co)
coroutine.resume(co)
print(coroutine.resume(co)) --输出 false cannot resume dead coroutine
co = coroutine.create(function(a,b) print("co",a+b,a-b) end)
print(coroutine.resume(co,20,10)) --输出 co 30 10 true
co = coroutine.create(function(a,b) coroutine.yield(a+b,a-b) end)
print(coroutine.resume(co,20,10)) --输出 true 30 10
co = coroutine.create(function() print("co",coroutine.yield()) end)
coroutine.resume(co) --什么都没输出
coroutine.resume(co,5,6) --输出 co 5 6
co = coroutine.create(function() return 6,7 end)
print(coroutine.resume(co)) --打印 6 7
使用协同程序
实现迭代器
实例:
function permgen(a,n)
n = n or #a
if n <= 1 then
coroutine.yield(a)
else
for i=1,n do
a[n],a[i] = a[i],a[n] --交换位置
permgen(a,n-1)
a[n],a[i] = a[i],a[n] --恢复位置
end
end
end
function permutations(a)
return coroutine.wrap(function() permgen(a) end)
end
function printResult(a)
for i=1,#a do
io.write(a[i]," ")
end
io.write("\n")
end
for p in permutations{"a","b","c"} do
printResult(p)
end
输出:
上一篇: Lua基础学习(五)https://blog.youkuaiyun.com/sun_zeliang/article/details/87459365