迭代器
迭代器是一種對象,它能夠來遍歷標(biāo)準(zhǔn)庫模板容器中的部分或全部元素,每個(gè)迭代器對象代表容器中確定的地址,在Lua中迭代器是一種支持指針類型的結(jié)構(gòu),他可以遍歷集合的每一個(gè)元素。
泛型for迭代器
泛型for自己內(nèi)部保存迭代函數(shù),實(shí)際上保存三個(gè)值:迭代函數(shù)、狀態(tài)常量、控制變量。
泛型for迭代器提供了集合的key/value對,
array = {"Hello","Tony","Chang"}
--for迭代器遍歷
for key,value in pairs(array)
do
print(key,value)
end
結(jié)果:
事實(shí)上使用Lua默認(rèn)提供的迭代函數(shù) ipairs,我們常常使用函數(shù)來描述迭代器,下面從函數(shù)角度分析pairs迭代器運(yùn)行。
(1). 初始化,獲取“in”后面表達(dá)式的三個(gè)值----迭代函數(shù)、狀態(tài)常量、控制變量(如果表示式返回家過不足三個(gè)則使用nil來補(bǔ)齊,如果返回?cái)?shù)值多,則自動忽略其余三個(gè)的數(shù)值)
(2) 將狀態(tài)常量和控制變量作為參數(shù)調(diào)用迭代函數(shù)。(在for結(jié)構(gòu)來說,狀態(tài)常量僅僅在初始化時(shí)候獲取它的數(shù)值并傳遞給迭代函數(shù))
(3)將迭代函數(shù)返回的數(shù)值賦給變量列表(每次調(diào)用函數(shù)就會返回集合的下一個(gè)元素)
(4) 如果返回的第一個(gè)數(shù)值為nil循環(huán)結(jié)束,否則執(zhí)行循環(huán)體
(5)回到第二步驟再次調(diào)用迭代函數(shù)
Lua迭代器的分類:
- 無狀態(tài)的迭代器
- 多狀態(tài)的迭代器
無狀態(tài)的迭代器
無狀態(tài)的迭代器是指不保留任何狀態(tài)的迭代器,因此在循環(huán)中我們可以利用無狀態(tài)迭代器避免創(chuàng)建閉包花費(fèi)額外的代價(jià)。
而每一次的迭代,迭代函數(shù)利用兩個(gè)變量(狀態(tài)常量和控制變量)的數(shù)值作為參數(shù)進(jìn)行調(diào)用。
其代表迭代器式ipairs/pair迭代器
--下面實(shí)現(xiàn)自定義迭代器來對元素內(nèi)容進(jìn)行平方
--自定義迭代函數(shù)
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber=currentNumber+1 --控制變量加一
return currentNumber,currentNumber*currentNumber
end
end
--作為迭代器調(diào)用
for i,n in square,3,0
do
print(i,n)
end
function iter(array,i)
i=i+1
local v=array[i]
if v then
return i,v
end
end
function ipiars(array)
return iter,array,0 --三個(gè)變量 函數(shù)、狀態(tài)常量、控制變量
end
根據(jù)這個(gè)原理,當(dāng)Lua調(diào)用ipairs(array)時(shí)候,獲取三個(gè)值:迭代函數(shù)iter、狀態(tài)常量array、控制變量的初始值0;然后調(diào)用iter(array,0)返回 1,array[1];
第二次調(diào)用iter(array,1) 返回2,array[2];直至返回的 n,nil 出現(xiàn)nil元素
多狀態(tài)的迭代器
很多情況下迭代器需要保存多個(gè)狀態(tài)信息而并不是簡單的狀態(tài)常量和控制變量,最簡單的方法是使用閉包。另一種辦法式將所有的信息狀態(tài)封裝到table中,將table作為迭代器的狀態(tài)常量。
array={"Hello","Tony","Chang"}
function elementIterator(collection)
local index=0
local count=#collection
--閉包函數(shù)
return function()
index=index+1
if index<=count
then
return collection[index]
end
end
end
for element in elementIterator(array)
do
print(element)
end
table(表格)
-
table索引可以是任意類型,但這個(gè)數(shù)值不能是nil
-
table大小不固定,根據(jù)自己需要進(jìn)行擴(kuò)容
-
使用table來解決模塊(module)、包(package)、和對象(Object)的。
--table的使用
--聲明
table1={}
table[1]="TonyChang"
--移除引用
table1=nil
--lua的垃圾回收會釋放內(nèi)存
驗(yàn)證table屬于一個(gè)存在于堆上的對象,(兩個(gè)索引指向同一個(gè)table,最后更改一個(gè)索引為空則對象還是存在,被另一個(gè)索引所指引著)
test = {}
print("test的類型是",type(test))
test[1]="Tony"
test["FirstName"]="Chang"
print("test[FirstNmae]",test["FirstName"])
testCopy=test
testCopy["FirstName"]="Zhang"
print("通過testCopy進(jìn)行修改之后-------------")
print("test[FirstNmae]",test["FirstName"])
--釋放副本指引指引
testCopy=nil
--仍舊可以通過原指引訪問table
print("test[1]")
--進(jìn)行遍歷打印
for key,value in pairs(test)
do
print(key,value)
end
Table中的操作
--table中的元素的連接
table2={"Hello","everyone","my","name","is","Tony"}
--直接連接
print(table.concat(table2))
--指定連接字符
print(table.concat(table2,", "))
--指定元素索引來連接
print(table.concat(table2,", ",1,2))
print(table.concat(table2,", ",1,3))
--table中的插入和移除
--在末尾插入
table.insert(table2,"Chang")
print(table.concat(table2,", "))
--指定索引處插入
table.insert(table2,2,"everybody")
print(table.concat(table2,", "))
--移除操作(默認(rèn)刪除最后一個(gè)元素)
table.remove(table2)
print(table.concat(table2,", "))
--移除指定索引的元素
table.remove(table2,3)
print(table.concat(table2,", "))
--table的排序
table3={"Hello","everyone","my","name","is","Tony"}
print("排序前")
for key,val in pairs(table3)
do
print(key,val)
end
--排序
table.sort(table3)
print("排序后")
for key,val in pairs(table3)
do
print(key,val)
end
--新建數(shù)組
array={}
--賦值
for i=1,5
do
array[i]=i*2
end
--遍歷查看
for key,val in pairs(array)
do
print(key,val)
end
--返回所有正key值中的最大值(Lua 5.2之后消失)
--注意是所有索引中最大值 如果沒有則返回0
print(table.maxn(array))
模塊和包
Lua中的模塊類似一個(gè)封裝庫,從Lua5.1開始,Lua加入標(biāo)磚的模塊管理機(jī)制,可以把一些公用的代碼放在一個(gè)文中中,以API接口形式在其它地方進(jìn)行調(diào)用,有利于降低代碼耦合度。
--模塊
--文件名稱為 module.lua
module={}
module.constant="這是一個(gè)常量"
function module.func1()
io.write("這是一個(gè)共有函數(shù)\n")
end
--私域函數(shù)不可以直接訪問
local function func2()
print("這是一個(gè)私有函數(shù)!")
end
--通過func3函數(shù)來訪問func2私域函數(shù)
function module.func3()
func2()
end
return module
--通過require函數(shù)來加載模塊
require("<module>")
require "<module>"
--以別名導(dǎo)入模塊
local nick=require("module")
nick.func3()
元表(Metatable)
在table中我們可以通過訪問對應(yīng)的key值來得到value值,但是無法從表的層面直接來操作(例如table1+table2)這樣的操作。而如果我們有了元表,就可以根據(jù)元表中定義的add加的函數(shù)來執(zhí)行兩個(gè)table之間的相加操作,因此給普通表table設(shè)置metatable元表可以完成table層面的操作!
--元表設(shè)置
mytable={} --普通表
mymetatable={} --元表
setmetatable(mytable,mymetatable) --將mymetatable設(shè)置為mytable的原表
--也可以直接設(shè)置
mytablb=setmetatable({},{})
--返回對象
getmetatable(mytable) --這里返回mymetatable
以下為元表常用的字段:
-
算術(shù)類元方法: 字段:__add(+), __mul(*), __ sub(-), __div(/), __unm, __mod(%), __pow, (__concat)
-
關(guān)系類元方法: 字段:__eq, __lt(<), __le(<=),其他Lua自動轉(zhuǎn)換 a~=b --> not(a == b) a > b --> b < a a >= b --> b <= a (注意NaN的情況)
-
table訪問的元方法: 字段: __index, __newindex
-
__index: 查詢:訪問表中不存的字段&
rawget(t, i) -
__newindex: 更新:向表中不存在索引賦值
rawset(t, k, v)
-index用來對表訪問
如果__index包含一個(gè)函數(shù)的話,Lua就會調(diào)用那個(gè)函數(shù),table和鍵會作為參數(shù)傳遞給函數(shù)。
--
table0=setmetatable({key1="value1"},{
__index = function(table,key)
if key=="key2" then
return "metatablevalue"
else
return nil
end
end
})
print(mytable.key1,mytable.key2)
-newindex元方法對表進(jìn)行更新
metatable1={}
table1=setmetatable({key1="value1"},{__newindex=metatable1})
print(table1.key1) -- 打印出value1
table1.key2="val2"
print(table1.key2) --此時(shí)未發(fā)現(xiàn)有key2 會打印nil
--然后會檢查元表中是否有__newindex方法,進(jìn)行調(diào)用新加
--最后打印出val2
print(metatable1.key2)
--再次設(shè)置新鍵
table1.key3="val3"
print(table1.key3)
print(metatable1.key3)
--上三行代碼重復(fù)驗(yàn)證
--如果不通過table訪問不存在的鍵,則__newindex函數(shù)只會調(diào)用但不會進(jìn)行賦值 所以訪問table元組
--的新索引值是nil
print(metatable1.key4)
--打印nil
由此可知,當(dāng)要訪問的是缺失的索引值,解釋器就會查找__newindex元方法,如果存在則調(diào)用這個(gè)函數(shù)(不進(jìn)行賦值操作)只有外部訪問時(shí)候賦值,其才會賦值。
在__newindex中通過調(diào)用rawset函數(shù)來更新table內(nèi)容
table6=setmetatable({key1="value1"},{__newindex=function(table,key,value)
rawset(table,key,"\""..value.."\"")
end
})
table6.key1="new value"
table6.key2=6
print(table6.key1)
print(table6.key2)--打印出6 而table的索引對應(yīng)數(shù)值寫入進(jìn)去
此時(shí)遍歷訪問table中內(nèi)容:
-兩table相加
--兩個(gè)table相加
--在元組中設(shè)置__add函數(shù)
table1=setmetatable({1,2,3},{__add=function(table1,table2)--雙下劃線
for i=1,table.maxn(table2)
do
table.insert(table1,table.maxn(table1)+1,table2[i])
end
return table1
end
})
secondtable={4,5,6}
table3=table1+secondtable
for k,v in pairs(table3)
do
print(k,v)
end
模式 | 描述(對應(yīng)符號) |
---|---|
__add | + |
__sub | - |
__mul | * |
__div | / |
__mod | % |
__unm | - |
_concat | .. |
__eq | == |
__It | < |
__Ie | <= |
__call元方法
call方法在調(diào)用一個(gè)值時(shí)候調(diào)用
--定義元方法來和
table4=setmetatable({10},{
__call=function(table1,table2)
sum=0
for i=1,table.maxn(table2) do
sum=sum+table2[i]
end
for i=1,table.maxn(table1) do
sum=sum+table1[i]
end
return sum
end
})
table5={12,13,14}
print(table4(table5))--直接傳入要操作的對象
協(xié)同程序
Lua的協(xié)同程序和線程比較類似,它擁有獨(dú)立的堆棧、獨(dú)立的局部變量、獨(dú)立的指令指針,同時(shí)又與其它協(xié)同程序共享全局變量以及其它大部分東西。
協(xié)程和線程的區(qū)別?
線程與協(xié)同程序的主要區(qū)別在于,一個(gè)具有多個(gè)線程的程序可以同時(shí)運(yùn)行幾個(gè)線程,而協(xié)同程序卻需要彼此協(xié)作的運(yùn)行。
在任一指定時(shí)刻只有一個(gè)協(xié)同程序在運(yùn)行,并且這個(gè)正在運(yùn)行的協(xié)同程序只有在明確的被要求掛起的時(shí)候才會被掛起。
協(xié)同程序有點(diǎn)類似同步的多線程,在等待同一個(gè)線程鎖的幾個(gè)線程有點(diǎn)類似協(xié)同。
--協(xié)程
--創(chuàng)建協(xié)程
coroutineTest=coroutine.create(
function(i)
print(i)
end
)
--啟動/重啟協(xié)程
coroutine.resume(coroutineTest,1)
print(coroutine.status(coroutineTest))--查看協(xié)程的狀態(tài)(掛起、運(yùn)行、死亡)
print('--------------------------')
--協(xié)程創(chuàng)造
--包裹一個(gè)函數(shù)的協(xié)程
coroutineTest2=coroutine.wrap(
function(i)
print(i)
end
)
coroutineTest2(1)--直接調(diào)用協(xié)程 執(zhí)行
print("--------------------")
--一個(gè)協(xié)程中的函數(shù)
--打印1,10
coroutineTest3=coroutine.create(
function()
for i=1,10 do
print(i)
if i==3 then
print(coroutine.status(coroutineTest3))
print(coroutine.running()) -- 返回運(yùn)行的協(xié)程
end
coroutine.yield() --協(xié)程掛起
end
end
)
--每次重新執(zhí)行則檢查上次函數(shù)執(zhí)行的中斷點(diǎn)
--繼續(xù)執(zhí)行循環(huán)邏輯
coroutine.resume(coroutineTest3)--打印1
coroutine.resume(coroutineTest3)--打印2
coroutine.resume(coroutineTest3)--打印3 并且打印線程狀態(tài) 和運(yùn)行協(xié)程的線程編號
print(coroutine.status(coroutineTest3)) --打印狀態(tài) suspended掛起狀態(tài)
print(coroutine.running()) --nil 現(xiàn)在沒有協(xié)程正在運(yùn)行
print("-------------------------------")
分析可知:coroutine.running可以得知,協(xié)程的底層還是由線程實(shí)現(xiàn)的。
當(dāng)create一個(gè)coroutine的時(shí)候就是在新線程中注冊一個(gè)事件,當(dāng)使用resume出發(fā)事件時(shí)候,create的
coroutine的函數(shù)就被執(zhí)行,當(dāng)遇到y(tǒng)ield的時(shí)候就表示掛起當(dāng)前線程,當(dāng)resume觸發(fā)事件時(shí)候,create的coroutine函數(shù)繼續(xù)被執(zhí)行,當(dāng)遇到y(tǒng)ield的時(shí)候就代表掛起當(dāng)前線程,等候再次被resume喚醒。
案例:
--協(xié)程中調(diào)用的函數(shù)
function sayNum(a)
print("sayNum:",a)
return coroutine.yield(2*a)
end
coroutineTest5=coroutine.create(function(a,b)
print("第一次協(xié)同程執(zhí)行輸出:",a,b)
local p=sayNum(a+1)
print("第二次協(xié)同程序執(zhí)行輸出:",p)
local p,q=coroutine.yield(a+b,a-b)
print("第三次協(xié)同程序執(zhí)行輸出:",p,q)
return b,"結(jié)束協(xié)程"
end)
print("main",coroutine.resume(coroutineTest5,1,10))
print("--------------------------------------------")
print("main",coroutine.resume(coroutineTest5,"r"))
print("--------------------------------------------")
print("main",coroutine.resume(coroutineTest5,"x","y"))
print("--------------------------------------------")
分析:
- 調(diào)用resum 協(xié)程喚醒(第一次執(zhí)行) resume喚醒成功返回true,(若喚醒失敗則返回false)(yield函數(shù)返回參數(shù)內(nèi)容)
- 協(xié)程運(yùn)行
- 運(yùn)行到y(tǒng)ield語句掛起(在sayName()函數(shù)中)
- 被掛起之后,第一次resume喚醒(第一個(gè)參數(shù)是要喚醒的協(xié)程,剩余的參數(shù)是接下來執(zhí)行語句參數(shù))
- 遇到y(tǒng)ield語句掛起,返回yield參數(shù)的內(nèi)容(a+b,a-b)
- 再次resume喚醒,繼續(xù)執(zhí)行打印語句(resume第二個(gè)函數(shù)是打印語句中的參數(shù))
- 遇到return 協(xié)程中函數(shù)邏輯執(zhí)行完畢!協(xié)程死亡
resume和yield的配合強(qiáng)大之處在于--resume處于主城中,它將外部狀態(tài)(數(shù)據(jù))傳入到程序(協(xié)程)內(nèi)部;
yield將內(nèi)部狀態(tài)(數(shù)據(jù))返回到主程序中。文章來源:http://www.zghlxwxcb.cn/news/detail-837660.html
使用協(xié)程來實(shí)現(xiàn)生產(chǎn)者--消費(fèi)者問題文章來源地址http://www.zghlxwxcb.cn/news/detail-837660.html
到了這里,關(guān)于Lua學(xué)習(xí)筆記之迭代器、table、模塊和包、元表和協(xié)程的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!