Lua语言入门(三)
协同程序
36、协同程序(coroutine)
4种状态:挂起(suspended)、运行(running)、死亡(dead)、正常(normal)
创建(挂起状态):
local co = coroutine.create(
function()
print("coroutine")
end)
启动或再次启动协程(状态由挂起改为运行):
coroutine.resume(co)
coroutine在创建的时候不会自动执行。
检查协程的状态:
coroutine.status(co)
协程在运行完之后,就处于死亡状态,再也无法返回。
使用yield:
local co = coroutine.create(
function()
for i=1,10 do
print(i)
coroutine.yield() --运行到这里让该协程挂起,之后通过调用coroutine.resume恢复它的运行
end
end
)
coroutine.resume(co) --1
coroutine.resume(co) --2
coroutine.resume(co) --3
coroutine.resume(co) --4
coroutine.resume(co) --5
当一个协程 A 唤醒另一个协程 B ,协程 A 就处于一个特殊状态,称为“正常状态”。
local co = coroutine.create(
function(a, b)
print("the first resume params: ", a, b); --在第一次调用resume,传递的额外参数都将视为协同程序主函数的参数;
print("resume params", coroutine.yield("yield return params")) --而yield返回值就是对应resume传入的参数
return "function return" --当一个协同程序结束时,主函数返回值都将作为resume的返回值。
end
)
print(coroutine.resume(co, 1, 2)) --调用resume后返回的内容,第一个值为true则表示没有错误,后面所有值都是对应yield传入的值
print(coroutine.resume(co, 3, 4, 5))
--[[
输出:
the first resume params: 1 2
true yield return params
resume params 3 4 5
true function return
]]
36、协程应用于生产者消费者模式(最好把代码运行一下,再去理解)
function receive(prod)
local status, value = coroutine.resume(prod)
return value
end
function send(x)
coroutine.yield(x)
end
function producer()
return coroutine.create(
function()
while true do
local x = io.read()
send(x)
end
end
)
end
function filter(prod)
return coroutine.create(
function()
for line = 1, math.huge do
local x = receive(prod)
x = string.format("%5d %s", line, x)
send(x)
end
end
)
end
function consumer(prod)
while true do
local x = receive(prod)
io.write(x, "\n")
end
end
p = producer()
f = filter(p)
consumer(f)
37、非抢先式多线程(协程):当一个协程运行时,无法从外部停止,只有协程显示的挂起(yield),才会停止。
常用数据结构
38、数组:以数字作为key的table,在lua中习惯用 1 作为数组起始,长度可变
a = {}
for i =1,10 do
a[i] = 0
end
print(#a) --计算数组长度
--直接创建并初始化数组
a = {7, 6, 5, 5, 7, 8, 9, 0, 0, 5, 3}
39、多维数组,可以用类似其它语言的方式表示多维,也可以利用一维数组表示。用稀疏矩阵表示一个图,table本身就是稀疏的,可以直接表示浪费内存。
mt = {}
for i=1,10 do
mt[i] = {}
for j=1,10 do
mt[i][j] = 0
end
end
遍历“稀疏矩阵”需要注意:一般使用pairs且只遍历那些非nil的元素。
pairs 和 ipairs 的区别:pairs 可以遍历表中所有的key,而ipairs 只能遍历到表中出现的一个不是整数的key
当然还有链表、队列、树、图等数据结构,这就不详细写了,这些东西和在其它语言里面是一样的
40、字符串连接:先把每个字符串存到一个数组里面,然后用table.concat连接,比用(..)连接更快更省
local a = {"A", "b", "C", "d", "E"}
local s = table.concat(a)
数据持久化
41、数据文件(读取):lua常常被用来做数据存取,在lua中,所谓的数据文件就是按一定格式定义的lua文件,把该“数据文件”加载进内存,就可以直接用lua代码解析了。
local count = 0
function Entry(b)
count = count + 1
print("load data call : "..b[1])
end
--dofile("data")
--data文件中就写如下的代码,这里为了简便,就直接把数据写在这里了。
Entry{--注意数据文件里面的Entry必须提前定义,其实数据文件里面的Entry在调用一个名叫Entry的函数
"A", "B", "C", "D", "E"
}
Entry{
"f", "g", "h", "i", "j"
}
print("number of entries : "..count)
42、数据持久化
保存无“环”形table:
function serialize(o)
if type(o) == "number" then
io.write(0)
elseif type(o) == "string" then
io.write(string.format("%q", o))
elseif type(o) == "table" then
io.write("{\n")
for k,v in pairs(o) do
io.write(" [")
serialize(k);
io.write("] = ")
serialize(v)
io.write(", \n")
end
io.write("}\n")
else
--其它情况
error("can not serialize a"..type(o))
end
end
serialize({a = 'A', b = 'Q', c = '1'})
保存有“环”形table:
43、元表:就是普通一个table,可以设置为其他表的元表,元表中可定义实现一系列的元方法
t = {}
t1 = {x = "a"}
setmetatable(t, t1) --把 t1 设置为 t 的元表
print(getmetatable(t)) --获得 t 的元表
44、元方法:定义于元表中的那些重载的方法
算术类元方法(__add(加法),__mul(乘法),__sub(减法),__div(除法),__unm(相反数),__mod(取模),__pow(幂)):
local t = {}
t.__add = function(a, b) --定义加法的元方法
return a["value"] + b["value"]
end
local obj1 = {value = 1}
setmetatable(obj1, t) --
local obj2 = {value = 2}
--setmetatable(obj1, t)
print(obj1 + obj2) --加法的时候,会检查它们其中任意一个的元表,只要有名叫__add的元方法,就会调用它定义的加法运算
关系类元方法(__eq(等于)、__lt(小于)、__le(等于)):
字符串输出元方法(__tostring):
local m = {}
m.__tostring = function()
return "meta function"
end
local a = {}
setmetatable(a, m)
print(a)
保护元表:使用用户既不能看也不能修改集合的元表,定义字段 __metatable
local m = {}
m.__metatable = "not your business" --保护元表
local a = {}
setmetatable(a, m)
print(getmetatable(a)) --not your business
setmetatable(a, m) --cannot change protected metatable
table访问的元方法:
__index元方法:当访问一个table中不存在的字段时,解释器会去查找元表中名叫__index的元方法,如果没有该方法,返回nil,否则由这个元方法提供结果。
local m = {}
m.__index = function()
return "index nil"
end
local a = {}
setmetatable(a, m)
print(a[1]) --index nil
__newindex元方法:当对一个table中不存在的索引赋值时,解释器就会查找__newindex元方法,如果元表中有该元方法,就调用它而不执行赋值。