?
本文檔使用 PHP中文網(wǎng)手冊 發(fā)布
本節(jié)介紹該語言的基本概念。
Lua是一種動態(tài)類型的語言。這意味著變量沒有類型; 只有值才有。該語言中沒有類型定義。所有的值都有自己的類型。
Lua中的所有值都是第一類對象。這意味著所有值都可以存儲在變量中,作為參數(shù)傳遞給其他函數(shù),并作為結(jié)果返回。
Lua有八種基本類型:nil,boolean,number,string,function,userdata,thread和table。類型nil有一個單一的值,nil,其主要屬性是不同于任何其他值; 它通常代表沒有有用的價值。布爾類型有兩個值,false和true。nil和false為假; 任何其他值都是真。類型number代表整數(shù)和實數(shù)(浮點數(shù))。類型string表示不可變的字節(jié)序列。Lua是8位清理:字符串可以包含任何8位值,包括嵌入的零(' \0
')。Lua也是編碼不可知的; 它不會假定字符串的內(nèi)容。
類型編號使用兩個內(nèi)部表示,或兩個子類型,一個稱為整數(shù),另一個稱為浮點。Lua明確規(guī)定了每個表示的使用時間,但它也根據(jù)需要自動進(jìn)行轉(zhuǎn)換(請參閱第3.4.3節(jié))。因此,程序員可能會選擇忽略整數(shù)和浮點數(shù)之間的差異,或者完全控制每個數(shù)字的表示。標(biāo)準(zhǔn)Lua使用64位整數(shù)和雙精度(64位)浮點數(shù),但您也可以編譯Lua,以便使用32位整數(shù)和/或單精度浮點數(shù)(32位)。對于小型機(jī)器和嵌入式系統(tǒng),整數(shù)和浮點數(shù)均為32位的選項特別具有吸引力。(請參閱LUA_32BITS
文件中的宏luaconf.h
。)
Lua可以調(diào)用(和操作)用Lua編寫的函數(shù)和用C編寫的函數(shù)(參見§3.4.10)。兩者都由類型函數(shù)表示。
提供類型userdata以允許將任意C數(shù)據(jù)存儲在Lua變量中。用戶數(shù)據(jù)值表示一塊原始內(nèi)存。有兩種用戶數(shù)據(jù):完整用戶數(shù)據(jù),它是由Lua管理的一塊內(nèi)存的對象,以及輕量級用戶數(shù)據(jù),它只是一個C指針值。用戶數(shù)據(jù)在Lua中沒有預(yù)定義的操作,除了賦值和身份測試。通過使用metatables,程序員可以定義完整的用戶數(shù)據(jù)值的操作(請參閱§2.4)。用戶數(shù)據(jù)值不能在Lua中創(chuàng)建或修改,只能通過C API。這保證了主機(jī)程序擁有的數(shù)據(jù)的完整性。
類型線程表示獨立的執(zhí)行線程,用于實現(xiàn)協(xié)程(請參閱第2.6節(jié))。Lua線程與操作系統(tǒng)線程無關(guān)。Lua支持所有系統(tǒng)上的協(xié)同程序,甚至是那些原生不支持線程的協(xié)程。
類型表實現(xiàn)了關(guān)聯(lián)數(shù)組,也就是說,不僅可以用數(shù)字對數(shù)組進(jìn)行索引,而且還可以使用除nil和NaN 之外的任何Lua值。(不是數(shù)字是用于表示未定義或不可表示的數(shù)字結(jié)果的特殊值,例如0/0
。)表可以是異構(gòu)的 ; 也就是說,它們可以包含所有類型的值(nil除外)。任何值為零的鍵都不被視為表格的一部分。相反,不屬于表的任何鍵都有相關(guān)的值nil。
表是Lua中唯一的數(shù)據(jù)結(jié)構(gòu)化機(jī)制; 它們可以用來表示普通數(shù)組,列表,符號表,集合,記錄,圖形,樹等。為了表示記錄,Lua使用字段名稱作為索引。該語言通過提供a.name
作為語法糖來支持這種表示a["name"]
。在Lua中創(chuàng)建表格有幾種方便的方法(參見§3.4.9)。
與索引一樣,表字段的值可以是任何類型。特別是,因為函數(shù)是第一類值,所以表字段可以包含函數(shù)。因此表格也可以攜帶方法(見§3.4.11)。
表格的索引遵循語言中原始平等的定義。表達(dá)式a[i]
和a[j]
表示同一個表元素當(dāng)且僅當(dāng)i
和j
原始相等(即沒有元方法時相等)。具體而言,具有整數(shù)值的浮點數(shù)等于它們各自的整數(shù)(例如,1.0 == 1
)。為了避免歧義,任何用作鍵的積分值的浮點數(shù)都被轉(zhuǎn)換為相應(yīng)的整數(shù)。例如,如果您編寫a[2.0] = true
,插入表中的實際密鑰將是整數(shù)2
。(另一方面,2和“ 2
”是不同的Lua值,因此表示不同的表項。)
表,函數(shù),線程和(完整)用戶數(shù)據(jù)值都是對象:變量實際上不包含這些值,只包含對它們的引用。賦值,參數(shù)傳遞和函數(shù)返回總是處理對這些值的引用; 這些操作并不意味著任何形式的副本。
庫函數(shù)type
返回一個描述給定值類型的字符串(請參閱第6.1節(jié))。
正如將在§3.2和§3.3.3中討論的那樣,任何對自由名稱的引用(也就是說,沒有綁定到任何聲明的名稱)都會var
被語法轉(zhuǎn)換為_ENV.var
。而且,每個塊都被編譯在一個名為外部局部變量_ENV
(請參閱§3.3.2)的范圍內(nèi),所以_ENV
它本身永遠(yuǎn)不會是塊中的空閑名稱。
盡管存在這個外部_ENV
變量和自由名稱的翻譯,但它_ENV
是一個完全正規(guī)的名稱。特別是,您可以使用該名稱定義新的變量和參數(shù)。每個對自由名稱的引用都_ENV
遵循Lua的通??梢娦砸?guī)則(參見§3.5),使用該程序中當(dāng)前可見的內(nèi)容。
任何用作值的表_ENV
稱為環(huán)境。
Lua擁有一個稱為全球環(huán)境的杰出環(huán)境。該值保存在C注冊表中的特殊索引處(請參閱第4.5節(jié))。在Lua中,全局變量_G
用這個相同的值進(jìn)行初始化。(_G
從未在內(nèi)部使用。)
當(dāng)Lua加載一個塊時,其_ENV
最大值的默認(rèn)值是全局環(huán)境(請參閱參考資料load
)。因此,默認(rèn)情況下,Lua代碼中的自由名稱是指全局環(huán)境中的條目(因此它們也被稱為全局變量)。而且,所有標(biāo)準(zhǔn)庫都在全球環(huán)境中加載,并且在那里有一些功能在該環(huán)境中運行。您可以使用load
(或loadfile
)加載具有不同環(huán)境的塊。(在C中,您必須加載塊,然后更改其第一個upvalue的值。)
由于Lua是一種嵌入式擴(kuò)展語言,所有Lua動作都從主機(jī)程序中的C代碼開始,從Lua庫中調(diào)用一個函數(shù)。(當(dāng)你使用Lua standalone時,lua
應(yīng)用程序就是宿主程序。)當(dāng)編譯或執(zhí)行Lua塊時發(fā)生錯誤時,控制權(quán)返回給主機(jī),主機(jī)可以采取適當(dāng)?shù)拇胧ㄈ绱蛴″e誤信息)。
通過調(diào)用error
函數(shù),Lua代碼可以明確地產(chǎn)生一個錯誤。如果您需要在Lua中發(fā)現(xiàn)錯誤,則可以使用pcall
或xpcall
在保護(hù)模式下調(diào)用給定的函數(shù)。
每當(dāng)出現(xiàn)錯誤時,錯誤對象(也稱為錯誤消息)將傳播有關(guān)錯誤的信息。Lua本身只會生成其錯誤對象是字符串的錯誤,但程序可能會將錯誤對象的任何值生成錯誤。由Lua程序或其主機(jī)來處理這些錯誤對象。
當(dāng)你使用xpcall
或者時lua_pcall
,你可能會給一個消息處理程序以在發(fā)生錯誤時被調(diào)用。該函數(shù)與原始錯誤對象一起調(diào)用并返回一個新的錯誤對象。在錯誤展開堆棧之前調(diào)用它,以便它可以收集有關(guān)錯誤的更多信息,例如通過檢查堆棧并創(chuàng)建堆?;厮荨T撓⑻幚沓绦蛉允苁鼙Wo(hù)呼叫的保護(hù); 所以,消息處理程序中的錯誤將再次調(diào)用消息處理程序。如果這個循環(huán)持續(xù)太久,Lua會打破它并返回一個合適的消息。(消息處理程序僅為常規(guī)運行時錯誤而調(diào)用,不會在調(diào)用終結(jié)器時調(diào)用內(nèi)存分配錯誤或錯誤。)
Lua中的每個值都可以有一個metatable。這個metatable是一個普通的Lua表,它定義了特定操作下原始值的行為。您可以通過在其metatable中設(shè)置特定字段來更改操作行為的某些方面。例如,當(dāng)一個非數(shù)字值是一個加法的操作數(shù)時,Lua會__add
在值的metatable 的字段“ ”中檢查一個函數(shù)。如果它找到一個,Lua調(diào)用這個函數(shù)來執(zhí)行加法。
metatable中每個事件的關(guān)鍵字是一個事件名稱前面加上兩個下劃線的字符串; 相應(yīng)的值稱為metamethods。在前面的例子中,鍵是“ __add
”,metamethod是執(zhí)行加法的函數(shù)。
您可以使用該getmetatable
函數(shù)查詢?nèi)魏沃档膍etatable 。Lua使用原始訪問查詢metatables中的元方法(請參閱參考資料rawget
)。因此,為了檢索ev
對象中的事件的metamethod o
,Lua會執(zhí)行與以下代碼等效的操作:
rawget(getmetatable(o) or {}, "__ev")
您可以使用該setmetatable
函數(shù)替換表格的元表。你不能從Lua代碼中改變其他類型的metatable(除了使用調(diào)試庫(§6.10)); 你應(yīng)該使用C API。
表和完整的userdata具有單獨的metatables(盡管多個表和userdata可以共享它們的metatables)。所有其他類型的值每種類型共享一個單一的metatable; 也就是說,對于所有數(shù)字都有一個單一的metatable,對于所有的字符串都有一個metatable,默認(rèn)情況下,一個值沒有metatable,但是字符串庫為字符串類型設(shè)置了一個metatable(見第6.4節(jié))。
metatable控制對象在算術(shù)運算,按位運算,順序比較,連接,長度操作,調(diào)用和索引中的表現(xiàn)。metatable也可以定義一個函數(shù),當(dāng)用戶數(shù)據(jù)或表被垃圾收集時(§2.5)被調(diào)用。
對于一元運算符(否定,長度和位非),元方法計算并用一個等于第一個操作數(shù)的虛擬第二操作數(shù)調(diào)用。這個額外的操作數(shù)僅僅是為了簡化Lua的內(nèi)部操作(通過使這些操作符像二進(jìn)制操作一樣)并且在將來的版本中可能會被刪除。(對于大多數(shù)用途,這個額外的操作數(shù)是不相關(guān)的。)
下面給出了由metatables控制的事件的詳細(xì)列表。每個操作都由其相應(yīng)的密鑰標(biāo)識。
__add
:加法(+
)操作。如果添加的操作數(shù)不是一個數(shù)字(也不是一個數(shù)字的強(qiáng)制字符串),Lua會嘗試調(diào)用一個metamethod。首先,Lua會檢查第一個操作數(shù)(即使它是有效的)。如果該操作數(shù)沒有定義metamethod __add
,那么Lua將檢查第二個操作數(shù)。如果Lua可以找到一個元方法,它將以兩個操作數(shù)作為參數(shù)來調(diào)用元方法,并且調(diào)用的結(jié)果(調(diào)整為一個值)是操作的結(jié)果。否則,它會引發(fā)錯誤。
__sub
:減法(-
)操作。與添加操作類似的行為。
__mul
:multiplication(*
)操作。與添加操作類似的行為。
__div
:division(/
)操作。與添加操作類似的行為。
__mod
:模(%
)操作。與添加操作類似的行為。
__pow
:指數(shù)運算(^
)。與添加操作類似的行為。
__unm
:否定(一元-
)操作。與添加操作類似的行為。
__idiv
:地板分區(qū)(//
)操作。與添加操作類似的行為。
__band
:按位AND(&
)操作。類似于加法操作的行為,除非Lua會嘗試元方法,如果任何操作數(shù)既不是整數(shù)也不是強(qiáng)制為整數(shù)的值(請參閱第3.4.3節(jié))。
__bor
:按位OR(|
)操作。類似于按位AND操作的行為。
__bxor
:按位異或(二進(jìn)制~
)操作。類似于按位AND操作的行為。
__bnot
:按位NOT(一元~
)操作。類似于按位AND操作的行為。
__shl
:按位左移(<<
)操作。類似于按位AND操作的行為。
__shr
:按位右移(>>
)操作。類似于按位AND操作的行為。
__concat
:concatenation(..
)操作。類似于加法操作的行為,除非Lua會嘗試一個元方法,如果任何操作數(shù)既不是字符串也不是數(shù)字(它總是對字符串進(jìn)行強(qiáng)制處理)。
__len
:length(#
)操作。如果對象不是字符串,Lua會嘗試它的元方法。如果有一個metamethod,Lua將該對象作為參數(shù)進(jìn)行調(diào)用,并且調(diào)用的結(jié)果(始終調(diào)整為一個值)是操作的結(jié)果。如果沒有元方法,但對象是一個表,那么Lua將使用表長度操作(請參閱第3.4.7節(jié))。否則,Lua會產(chǎn)生一個錯誤。
__eq
:equal(==
)操作。行為類似于加法操作,除非Lua只會在比較的值都是表或全部用戶數(shù)據(jù)并且它們不是基本相等時才嘗試metamethod。調(diào)用的結(jié)果總是轉(zhuǎn)換為布爾值。
__lt
:小于(<
)操作。類似于加法操作的行為,除非Lua僅在比較的值既不是數(shù)字也不是兩個字符串時才嘗試metamethod。調(diào)用的結(jié)果總是轉(zhuǎn)換為布爾值。
__le
:不等于(<=
)的操作。與其他操作不同,不太平等的操作可以使用兩個不同的事件。首先,Lua __le
在兩個操作數(shù)中尋找metamethod,就像在少于操作中一樣。如果它找不到這樣的metamethod,那么它會嘗試__lt
metamethod,假設(shè)它a <= b
相當(dāng)于not (b < a)
。與其他比較運算符一樣,結(jié)果始終是布爾值。(這個__lt
事件的使用可以在將來的版本中被刪除;它也比真實的__le
元方法慢)。
__index
:索引訪問table[key]
。這個事件發(fā)生在table
不是表格或者key
不存在時table
。metamethod被抬頭table
。盡管名稱,這個事件的metamethod可以是一個函數(shù)或表。如果它是一個函數(shù),它被稱為與table
和key
作為參數(shù),并且該呼叫(調(diào)整到一個值)的結(jié)果是該操作的結(jié)果。如果它是一個表格,最終結(jié)果就是將此表格編入索引的結(jié)果key
。(這個索引是規(guī)則的,不是原始的,因此可以觸發(fā)另一個元方法。)
__newindex
:索引分配table[key] = value
。和索引事件一樣,這個事件發(fā)生在table
不是表格或者key
不存在時table
。metamethod被抬頭table
。與索引一樣,此事件的元方法可以是函數(shù)也可以是表格。如果它是一個功能,它被稱為用table
,key
以及value
作為參數(shù)。如果它是一個表,Lua會使用相同的鍵和值對此表執(zhí)行索引分配。(這個任務(wù)是規(guī)則的,不是原始的,因此可以觸發(fā)另一個元方法。)每當(dāng)有一個__newindex
元方法時,Lua就不執(zhí)行原語分配。(如有必要,metamethod本身可以打電話rawset
來完成作業(yè)。)
__call
:通話操作func(args)
。當(dāng)Lua嘗試調(diào)用非函數(shù)值(即,func
不是函數(shù))時,會發(fā)生此事件。metamethod被抬頭func
。如果存在,metamethod被稱為func
第一個參數(shù),然后是原始調(diào)用(args
)的參數(shù)。調(diào)用的所有結(jié)果都是操作的結(jié)果。(這是允許多個結(jié)果的唯一元方法。)
在將其設(shè)置為某個對象的metatable之前,將所有需要的metamethods添加到表中是一種很好的做法。特別是,__gc
metamethod只有在遵循這個順序時才起作用(見§2.5.1)。
由于metatables是常規(guī)表,因此它們可以包含任意字段,而不僅僅是上面定義的事件名稱。標(biāo)準(zhǔn)庫中的一些功能(例如tostring
)使用metatables中的其他字段來實現(xiàn)自己的目的。
Lua執(zhí)行自動內(nèi)存管理。這意味著您不必?fù)?dān)心為新對象分配內(nèi)存或在不再需要對象時釋放內(nèi)存。Lua通過運行垃圾回收器來自動管理內(nèi)存以收集所有死對象(即,不再可從Lua訪問的對象)。Lua使用的所有內(nèi)存都受自動管理:字符串,表格,用戶數(shù)據(jù),函數(shù),線程,內(nèi)部結(jié)構(gòu)等。
Lua實現(xiàn)了一個增量式標(biāo)記和掃描收集器。它使用兩個數(shù)字來控制其垃圾收集周期:垃圾收集器暫停和垃圾收集器步驟乘數(shù)。兩者均以百分點為單位(例如,值100表示內(nèi)部值為1)。
垃圾收集器暫??刂剖占髟陂_始新循環(huán)之前等待的時間。較大的值使收集器不那么積極。小于100的值意味著收集器不會等待開始新的循環(huán)。值為200意味著收集器在開始新周期之前等待使用的總內(nèi)存翻倍。
垃圾收集器步驟乘法器控制收集器相對于內(nèi)存分配的相對速度。較大的值使收集器更具侵略性,但也會增加每個增量步驟的大小。您不應(yīng)該使用小于100的值,因為它們會使收集器太慢,并可能導(dǎo)致收集器永遠(yuǎn)不會完成一個循環(huán)。默認(rèn)值是200,這意味著收集器以內(nèi)存分配速度的“兩倍”運行。
如果您將步驟乘數(shù)設(shè)置為非常大的數(shù)字(大于程序可以使用的最大字節(jié)數(shù)的10%),則收集器的行為就像是一個停止世界的收集器。如果您將暫停設(shè)置為200,那么收集器的行為與舊版本的Lua版本相同,每當(dāng)Lua將其內(nèi)存使用量翻倍時,會執(zhí)行完整的收集。
您可以通過lua_gc
在C或collectgarbage
Lua中調(diào)用來更改這些數(shù)字。您也可以使用這些功能直接控制收集器(例如,停止并重新啟動它)。
您可以為表格設(shè)置垃圾收集器元方法,并使用C API為完整的用戶數(shù)據(jù)設(shè)置(請參閱第2.4節(jié))。這些metamethods也被稱為finalizer。終結(jié)器允許您將Lua的垃圾回收與外部資源管理(如關(guān)閉文件,網(wǎng)絡(luò)或數(shù)據(jù)庫連接,或釋放自己的內(nèi)存)進(jìn)行協(xié)調(diào)。
對于要收集的對象(表或用戶數(shù)據(jù))進(jìn)行最終確定時,您必須將其標(biāo)記為最終確定。在設(shè)置其元數(shù)據(jù)時,您將對象標(biāo)記為最終化,并且metatable具有由字符串“ __gc
” 索引的字段。請注意,如果您在沒有__gc
字段的情況下設(shè)置了metatable ,然后在metatable中創(chuàng)建該字段,則該對象將不會標(biāo)記為最終化。
當(dāng)一個標(biāo)記的對象變成垃圾時,垃圾收集器不會立即收集它。相反,Lua把它列入清單。收集完成后,Lua會瀏覽該列表。對于列表中的每個對象,它檢查對象的__gc
元方法:如果它是一個函數(shù),則Lua將該對象作為其單個參數(shù)進(jìn)行調(diào)用; 如果metamethod不是函數(shù),那么Lua會忽略它。
在每個垃圾收集周期結(jié)束時,以相反的順序調(diào)用對象的終結(jié)器,以便在該周期中收集的對象被標(biāo)記為最終確定; 也就是說,要被調(diào)用的第一個終結(jié)器是與程序中最后標(biāo)記的對象相關(guān)聯(lián)的終結(jié)器。每個終結(jié)器的執(zhí)行可能會在執(zhí)行常規(guī)代碼的任何時候發(fā)生。
因為所收集的對象必須仍然被終結(jié)使用,該對象(并且只能通過其可訪問的其他對象),必須復(fù)活由Lua中。通常,這種復(fù)活是暫時的,并且在下一次垃圾收集循環(huán)中釋放對象內(nèi)存。但是,如果終結(jié)器將對象存儲在某個全局位置(例如全局變量)中,則復(fù)活是永久的。此外,如果終結(jié)器再次將終結(jié)對象標(biāo)記為終結(jié)對象,則在下一個對象無法訪問的周期中將再次調(diào)用終結(jié)器。在任何情況下,只有在對象不可訪問且未標(biāo)記為完成的GC循環(huán)中才釋放對象內(nèi)存。
當(dāng)你關(guān)閉一個狀態(tài)時(參見lua_close
),Lua調(diào)用所有標(biāo)記為最終化的對象的終結(jié)器,按照它們被標(biāo)記的相反順序。如果任何終結(jié)器在該階段標(biāo)記用于收集的對象,則這些標(biāo)記不起作用。
一個弱表是一個表,它的元素是弱引用。垃圾收集器忽略弱引用。換句話說,如果對象的唯一引用是弱引用,那么垃圾收集器將收集該對象。
弱表可以具有弱鍵,弱值或兩者。具有較弱值的表允許收集其值,但會阻止收集其密鑰。具有弱鍵和弱值的表格允許集合鍵和值。在任何情況下,如果收集密鑰或值,則將整個對從表中移除。桌子的弱點__mode
由其metatable字段控制。如果該__mode
字段是包含字符' k
' 的字符串,則表中的鍵很弱。如果__mode
包含“ v
',表中的值很弱。
具有弱鍵和強(qiáng)值的表格也被稱為ephemeron表格。在ephemeron表中,只有在密鑰可達(dá)的情況下才認(rèn)為該值可訪問。特別是,如果只有一個鍵的引用通過它的值,那么這個鍵被刪除。
只有在下一個收集周期中,表中任何弱點的變化才會生效。特別是,如果您將弱點更改為更強(qiáng)大的模式,則Lua可能會在更改生效之前從該表中收集一些項目。
只有具有顯式構(gòu)造的對象才會從弱表中刪除。值(如數(shù)字和亮C函數(shù))不受垃圾回收處理,因此不會從弱表中刪除(除非收集其相關(guān)值)。雖然字符串需要垃圾回收,但它們沒有明確的構(gòu)造,因此不會從弱表中刪除。
復(fù)活對象(即,正在完成的對象和只能通過正在完成的對象才可訪問的對象)在弱表中具有特殊行為。在運行終結(jié)器之前,它們將從弱值中移除,但是在運行終結(jié)器之后,只有在下一個集合中才從弱鍵中移除它們,而這些對象實際上已被釋放。此行為允許終結(jié)器通過弱表訪問與對象關(guān)聯(lián)的屬性。
如果收集周期中的復(fù)活對象中存在弱表,那么在下一個周期之前可能無法正確清除。
Lua支持協(xié)程,也稱為協(xié)作多線程。Lua中的協(xié)程表示一個獨立的執(zhí)行線程。然而,與多線程系統(tǒng)中的線程不同,協(xié)程只通過顯式調(diào)用yield函數(shù)來暫停執(zhí)行。
通過調(diào)用創(chuàng)建協(xié)程coroutine.create
。它的唯一參數(shù)是一個函數(shù),它是協(xié)程的主要功能。該create
函數(shù)只創(chuàng)建一個新的協(xié)程并返回一個句柄(一個線程類型的對象); 它不啟動協(xié)程。
你通過調(diào)用來執(zhí)行協(xié)程coroutine.resume
。當(dāng)您第一次調(diào)用時coroutine.resume
,將第一個參數(shù)作為返回的線程傳遞coroutine.create
,協(xié)程通過調(diào)用其主函數(shù)來開始執(zhí)行。傳遞給它的額外參數(shù)coroutine.resume
作為參數(shù)傳遞給該函數(shù)。協(xié)程開始運行后,它會一直運行,直到它終止或退出。
協(xié)程可以通過兩種方式終止它的執(zhí)行:通常,當(dāng)主函數(shù)返回(顯式或隱式地,在最后一條指令之后)時; 并且在異常情況下,如果存在無保護(hù)的錯誤。在正常終止的情況下,coroutine.resume
返回真,再加上協(xié)程主函數(shù)返回的任何值。如果有錯誤,則coroutine.resume
返回false加錯誤對象。
協(xié)程通過調(diào)用產(chǎn)生收益coroutine.yield
。當(dāng)協(xié)程產(chǎn)生時,coroutine.resume
即使產(chǎn)量發(fā)生在嵌套函數(shù)調(diào)用(即,不在主函數(shù)中,而是在由主函數(shù)直接或間接調(diào)用的函數(shù)中),也立即產(chǎn)生相應(yīng)的返回。在yield的情況下,coroutine.resume
也返回true,加上傳遞給它的值coroutine.yield
。下一次恢復(fù)同一個協(xié)程時,它會繼續(xù)執(zhí)行它的執(zhí)行點,并調(diào)用coroutine.yield
返回傳遞給它的額外參數(shù)coroutine.resume
。
類似coroutine.create
的coroutine.wrap
功能還創(chuàng)建了一個協(xié)程,但不是返回協(xié)同程序本身,它返回一個函數(shù),調(diào)用它時,恢復(fù)協(xié)程。傳遞給這個函數(shù)的任何參數(shù)都是作為額外的參數(shù)coroutine.resume
。coroutine.wrap
返回由coroutine.resume
第一個返回的所有值(布爾錯誤代碼)。不像coroutine.resume
,coroutine.wrap
不會發(fā)現(xiàn)錯誤; 任何錯誤都會傳播給調(diào)用者。
作為協(xié)程的工作原理的例子,請考慮以下代碼:
function foo (a) print("foo", a) return coroutine.yield(2*a)end co = coroutine.create(function (a,b) print("co-body", a, b) local r = foo(a+1) print("co-body", r) local r, s = coroutine.yield(a+b, a-b) print("co-body", r, s) return b, "end"end)print("main", coroutine.resume(co, 1, 10))print("main", coroutine.resume(co, "r"))print("main", coroutine.resume(co, "x", "y"))print("main", coroutine.resume(co, "x", "y"))
當(dāng)你運行它時,它會產(chǎn)生以下輸出:
co-body 1 10foo 2main true 4co-body r main true 11 -9co-body x y main true 10 end main false cannot resume dead coroutine
您還可以創(chuàng)建和操作通過C API協(xié)同程序:看功能lua_newthread
,lua_resume
和lua_yield
。