亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

テキスト

本節(jié)介紹該語言的基本概念。

2.1 – Values and Types

Lua是一種動(dòng)態(tài)類型的語言。這意味著變量沒有類型; 只有值才有。該語言中沒有類型定義。所有的值都有自己的類型。

Lua中的所有值都是第一類對(duì)象。這意味著所有值都可以存儲(chǔ)在變量中,作為參數(shù)傳遞給其他函數(shù),并作為結(jié)果返回。

Lua有八種基本類型:nil,booleannumber,string,function,userdata,threadtable。類型nil有一個(gè)單一的值,nil,其主要屬性是不同于任何其他值; 它通常代表沒有有用的價(jià)值。布爾類型有兩個(gè)值,falsetrue。nil和false為假; 任何其他值都是真。類型number代表整數(shù)和實(shí)數(shù)(浮點(diǎn)數(shù))。類型string表示不可變的字節(jié)序列。Lua是8位清理:字符串可以包含任何8位值,包括嵌入的零(' \0')。Lua也是編碼不可知的; 它不會(huì)假定字符串的內(nèi)容。

類型編號(hào)使用兩個(gè)內(nèi)部表示,或兩個(gè)子類型,一個(gè)稱為整數(shù),另一個(gè)稱為浮點(diǎn)。Lua明確規(guī)定了每個(gè)表示的使用時(shí)間,但它也根據(jù)需要自動(dòng)進(jìn)行轉(zhuǎn)換(請(qǐng)參閱第3.4.3節(jié))。因此,程序員可能會(huì)選擇忽略整數(shù)和浮點(diǎn)數(shù)之間的差異,或者完全控制每個(gè)數(shù)字的表示。標(biāo)準(zhǔn)Lua使用64位整數(shù)和雙精度(64位)浮點(diǎn)數(shù),但您也可以編譯Lua,以便使用32位整數(shù)和/或單精度浮點(diǎn)數(shù)(32位)。對(duì)于小型機(jī)器和嵌入式系統(tǒng),整數(shù)和浮點(diǎn)數(shù)均為32位的選項(xiàng)特別具有吸引力。(請(qǐng)參閱LUA_32BITS文件中的宏luaconf.h。)

Lua可以調(diào)用(和操作)用Lua編寫的函數(shù)和用C編寫的函數(shù)(參見§3.4.10)。兩者都由類型函數(shù)表示。

提供類型userdata以允許將任意C數(shù)據(jù)存儲(chǔ)在Lua變量中。用戶數(shù)據(jù)值表示一塊原始內(nèi)存。有兩種用戶數(shù)據(jù):完整用戶數(shù)據(jù),它是由Lua管理的一塊內(nèi)存的對(duì)象,以及輕量級(jí)用戶數(shù)據(jù),它只是一個(gè)C指針值。用戶數(shù)據(jù)在Lua中沒有預(yù)定義的操作,除了賦值和身份測(cè)試。通過使用metatables,程序員可以定義完整的用戶數(shù)據(jù)值的操作(請(qǐng)參閱§2.4)。用戶數(shù)據(jù)值不能在Lua中創(chuàng)建或修改,只能通過C API。這保證了主機(jī)程序擁有的數(shù)據(jù)的完整性。

類型線程表示獨(dú)立的執(zhí)行線程,用于實(shí)現(xiàn)協(xié)程(請(qǐng)參閱第2.6節(jié))。Lua線程與操作系統(tǒng)線程無關(guān)。Lua支持所有系統(tǒng)上的協(xié)同程序,甚至是那些原生不支持線程的協(xié)程。

類型表實(shí)現(xiàn)了關(guān)聯(lián)數(shù)組,也就是說,不僅可以用數(shù)字對(duì)數(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ù)組,列表,符號(hào)表,集合,記錄,圖形,樹等。為了表示記錄,Lua使用字段名稱作為索引。該語言通過提供a.name作為語法糖來支持這種表示a["name"]。在Lua中創(chuàng)建表格有幾種方便的方法(參見§3.4.9)。

與索引一樣,表字段的值可以是任何類型。特別是,因?yàn)楹瘮?shù)是第一類值,所以表字段可以包含函數(shù)。因此表格也可以攜帶方法(見§3.4.11)。

表格的索引遵循語言中原始平等的定義。表達(dá)式a[i]a[j]表示同一個(gè)表元素當(dāng)且僅當(dāng)ij原始相等(即沒有元方法時(shí)相等)。具體而言,具有整數(shù)值的浮點(diǎn)數(shù)等于它們各自的整數(shù)(例如,1.0 == 1)。為了避免歧義,任何用作鍵的積分值的浮點(diǎn)數(shù)都被轉(zhuǎn)換為相應(yīng)的整數(shù)。例如,如果您編寫a[2.0] = true,插入表中的實(shí)際密鑰將是整數(shù)2。(另一方面,2和“ 2”是不同的Lua值,因此表示不同的表項(xiàng)。)

表,函數(shù),線程和(完整)用戶數(shù)據(jù)值都是對(duì)象:變量實(shí)際上不包含這些值,只包含對(duì)它們的引用。賦值,參數(shù)傳遞和函數(shù)返回總是處理對(duì)這些值的引用; 這些操作并不意味著任何形式的副本。

庫函數(shù)type返回一個(gè)描述給定值類型的字符串(請(qǐng)參閱第6.1節(jié))。

2.2 – Environments and the Global Environment

正如將在§3.2和§3.3.3中討論的那樣,任何對(duì)自由名稱的引用(也就是說,沒有綁定到任何聲明的名稱)都會(huì)var被語法轉(zhuǎn)換為_ENV.var。而且,每個(gè)塊都被編譯在一個(gè)名為外部局部變量_ENV(請(qǐng)參閱§3.3.2)的范圍內(nèi),所以_ENV它本身永遠(yuǎn)不會(huì)是塊中的空閑名稱。

盡管存在這個(gè)外部_ENV變量和自由名稱的翻譯,但它_ENV是一個(gè)完全正規(guī)的名稱。特別是,您可以使用該名稱定義新的變量和參數(shù)。每個(gè)對(duì)自由名稱的引用都_ENV遵循Lua的通??梢娦砸?guī)則(參見§3.5),使用該程序中當(dāng)前可見的內(nèi)容。

任何用作值的表_ENV稱為環(huán)境。

Lua擁有一個(gè)稱為全球環(huán)境的杰出環(huán)境。該值保存在C注冊(cè)表中的特殊索引處(請(qǐng)參閱第4.5節(jié))。在Lua中,全局變量_G用這個(gè)相同的值進(jìn)行初始化。(_G從未在內(nèi)部使用。)

當(dāng)Lua加載一個(gè)塊時(shí),其_ENV最大值的默認(rèn)值是全局環(huán)境(請(qǐng)參閱參考資料load)。因此,默認(rèn)情況下,Lua代碼中的自由名稱是指全局環(huán)境中的條目(因此它們也被稱為全局變量)。而且,所有標(biāo)準(zhǔn)庫都在全球環(huán)境中加載,并且在那里有一些功能在該環(huán)境中運(yùn)行。您可以使用load(或loadfile)加載具有不同環(huán)境的塊。(在C中,您必須加載塊,然后更改其第一個(gè)upvalue的值。)

2.3 – Error Handling

由于Lua是一種嵌入式擴(kuò)展語言,所有Lua動(dòng)作都從主機(jī)程序中的C代碼開始,從Lua庫中調(diào)用一個(gè)函數(shù)。(當(dāng)你使用Lua standalone時(shí),lua應(yīng)用程序就是宿主程序。)當(dāng)編譯或執(zhí)行Lua塊時(shí)發(fā)生錯(cuò)誤時(shí),控制權(quán)返回給主機(jī),主機(jī)可以采取適當(dāng)?shù)拇胧ㄈ绱蛴″e(cuò)誤信息)。

通過調(diào)用error函數(shù),Lua代碼可以明確地產(chǎn)生一個(gè)錯(cuò)誤。如果您需要在Lua中發(fā)現(xiàn)錯(cuò)誤,則可以使用pcallxpcall保護(hù)模式下調(diào)用給定的函數(shù)。

每當(dāng)出現(xiàn)錯(cuò)誤時(shí),錯(cuò)誤對(duì)象(也稱為錯(cuò)誤消息)將傳播有關(guān)錯(cuò)誤的信息。Lua本身只會(huì)生成其錯(cuò)誤對(duì)象是字符串的錯(cuò)誤,但程序可能會(huì)將錯(cuò)誤對(duì)象的任何值生成錯(cuò)誤。由Lua程序或其主機(jī)來處理這些錯(cuò)誤對(duì)象。

當(dāng)你使用xpcall或者時(shí)lua_pcall,你可能會(huì)給一個(gè)消息處理程序以在發(fā)生錯(cuò)誤時(shí)被調(diào)用。該函數(shù)與原始錯(cuò)誤對(duì)象一起調(diào)用并返回一個(gè)新的錯(cuò)誤對(duì)象。在錯(cuò)誤展開堆棧之前調(diào)用它,以便它可以收集有關(guān)錯(cuò)誤的更多信息,例如通過檢查堆棧并創(chuàng)建堆?;厮?。該消息處理程序仍受受保護(hù)呼叫的保護(hù); 所以,消息處理程序中的錯(cuò)誤將再次調(diào)用消息處理程序。如果這個(gè)循環(huán)持續(xù)太久,Lua會(huì)打破它并返回一個(gè)合適的消息。(消息處理程序僅為常規(guī)運(yùn)行時(shí)錯(cuò)誤而調(diào)用,不會(huì)在調(diào)用終結(jié)器時(shí)調(diào)用內(nèi)存分配錯(cuò)誤或錯(cuò)誤。)

2.4 – Metatables and Metamethods

Lua中的每個(gè)值都可以有一個(gè)metatable。這個(gè)metatable是一個(gè)普通的Lua表,它定義了特定操作下原始值的行為。您可以通過在其metatable中設(shè)置特定字段來更改操作行為的某些方面。例如,當(dāng)一個(gè)非數(shù)字值是一個(gè)加法的操作數(shù)時(shí),Lua會(huì)__add在值的metatable 的字段“ ”中檢查一個(gè)函數(shù)。如果它找到一個(gè),Lua調(diào)用這個(gè)函數(shù)來執(zhí)行加法。

metatable中每個(gè)事件的關(guān)鍵字是一個(gè)事件名稱前面加上兩個(gè)下劃線的字符串; 相應(yīng)的值稱為metamethods。在前面的例子中,鍵是“ __add”,metamethod是執(zhí)行加法的函數(shù)。

您可以使用該getmetatable函數(shù)查詢?nèi)魏沃档膍etatable 。Lua使用原始訪問查詢metatables中的元方法(請(qǐng)參閱參考資料rawget)。因此,為了檢索ev對(duì)象中的事件的metamethod o,Lua會(huì)執(zhí)行與以下代碼等效的操作:

rawget(getmetatable(o) or {}, "__ev")

您可以使用該setmetatable函數(shù)替換表格的元表。你不能從Lua代碼中改變其他類型的metatable(除了使用調(diào)試庫(§6.10)); 你應(yīng)該使用C API。

表和完整的userdata具有單獨(dú)的metatables(盡管多個(gè)表和userdata可以共享它們的metatables)。所有其他類型的值每種類型共享一個(gè)單一的metatable; 也就是說,對(duì)于所有數(shù)字都有一個(gè)單一的metatable,對(duì)于所有的字符串都有一個(gè)metatable,默認(rèn)情況下,一個(gè)值沒有metatable,但是字符串庫為字符串類型設(shè)置了一個(gè)metatable(見第6.4節(jié))。

metatable控制對(duì)象在算術(shù)運(yùn)算,按位運(yùn)算,順序比較,連接,長度操作,調(diào)用和索引中的表現(xiàn)。metatable也可以定義一個(gè)函數(shù),當(dāng)用戶數(shù)據(jù)或表被垃圾收集時(shí)(§2.5)被調(diào)用。

對(duì)于一元運(yùn)算符(否定,長度和位非),元方法計(jì)算并用一個(gè)等于第一個(gè)操作數(shù)的虛擬第二操作數(shù)調(diào)用。這個(gè)額外的操作數(shù)僅僅是為了簡化Lua的內(nèi)部操作(通過使這些操作符像二進(jìn)制操作一樣)并且在將來的版本中可能會(huì)被刪除。(對(duì)于大多數(shù)用途,這個(gè)額外的操作數(shù)是不相關(guān)的。)

下面給出了由metatables控制的事件的詳細(xì)列表。每個(gè)操作都由其相應(yīng)的密鑰標(biāo)識(shí)。

  • __add:加法(+)操作。如果添加的操作數(shù)不是一個(gè)數(shù)字(也不是一個(gè)數(shù)字的強(qiáng)制字符串),Lua會(huì)嘗試調(diào)用一個(gè)metamethod。首先,Lua會(huì)檢查第一個(gè)操作數(shù)(即使它是有效的)。如果該操作數(shù)沒有定義metamethod __add,那么Lua將檢查第二個(gè)操作數(shù)。如果Lua可以找到一個(gè)元方法,它將以兩個(gè)操作數(shù)作為參數(shù)來調(diào)用元方法,并且調(diào)用的結(jié)果(調(diào)整為一個(gè)值)是操作的結(jié)果。否則,它會(huì)引發(fā)錯(cuò)誤。

  • __sub:減法(-)操作。與添加操作類似的行為。

  • __mul:multiplication(*)操作。與添加操作類似的行為。

  • __div:division(/)操作。與添加操作類似的行為。

  • __mod:模(%)操作。與添加操作類似的行為。

  • __pow:指數(shù)運(yùn)算(^)。與添加操作類似的行為。

  • __unm:否定(一元-)操作。與添加操作類似的行為。

  • __idiv:地板分區(qū)(//)操作。與添加操作類似的行為。

  • __band:按位AND(&)操作。類似于加法操作的行為,除非Lua會(huì)嘗試元方法,如果任何操作數(shù)既不是整數(shù)也不是強(qiáng)制為整數(shù)的值(請(qǐng)參閱第3.4.3節(jié))。

  • __bor:按位OR(|)操作。類似于按位AND操作的行為。

  • __bxor:按位異或(二進(jìn)制~)操作。類似于按位AND操作的行為。

  • __bnot:按位NOT(一元~)操作。類似于按位AND操作的行為。

  • __shl:按位左移(<<)操作。類似于按位AND操作的行為。

  • __shr:按位右移(>>)操作。類似于按位AND操作的行為。

  • __concat:concatenation(..)操作。類似于加法操作的行為,除非Lua會(huì)嘗試一個(gè)元方法,如果任何操作數(shù)既不是字符串也不是數(shù)字(它總是對(duì)字符串進(jìn)行強(qiáng)制處理)。

  • __len:length(#)操作。如果對(duì)象不是字符串,Lua會(huì)嘗試它的元方法。如果有一個(gè)metamethod,Lua將該對(duì)象作為參數(shù)進(jìn)行調(diào)用,并且調(diào)用的結(jié)果(始終調(diào)整為一個(gè)值)是操作的結(jié)果。如果沒有元方法,但對(duì)象是一個(gè)表,那么Lua將使用表長度操作(請(qǐng)參閱第3.4.7節(jié))。否則,Lua會(huì)產(chǎn)生一個(gè)錯(cuò)誤。

  • __eq:equal(==)操作。行為類似于加法操作,除非Lua只會(huì)在比較的值都是表或全部用戶數(shù)據(jù)并且它們不是基本相等時(shí)才嘗試metamethod。調(diào)用的結(jié)果總是轉(zhuǎn)換為布爾值。

  • __lt:小于(<)操作。類似于加法操作的行為,除非Lua僅在比較的值既不是數(shù)字也不是兩個(gè)字符串時(shí)才嘗試metamethod。調(diào)用的結(jié)果總是轉(zhuǎn)換為布爾值。

  • __le:不等于(<=)的操作。與其他操作不同,不太平等的操作可以使用兩個(gè)不同的事件。首先,Lua __le在兩個(gè)操作數(shù)中尋找metamethod,就像在少于操作中一樣。如果它找不到這樣的metamethod,那么它會(huì)嘗試__ltmetamethod,假設(shè)它a <= b相當(dāng)于not (b < a)。與其他比較運(yùn)算符一樣,結(jié)果始終是布爾值。(這個(gè)__lt事件的使用可以在將來的版本中被刪除;它也比真實(shí)的__le元方法慢)。

  • __index:索引訪問table[key]。這個(gè)事件發(fā)生在table不是表格或者key不存在時(shí)table。metamethod被抬頭table。盡管名稱,這個(gè)事件的metamethod可以是一個(gè)函數(shù)或表。如果它是一個(gè)函數(shù),它被稱為與tablekey作為參數(shù),并且該呼叫(調(diào)整到一個(gè)值)的結(jié)果是該操作的結(jié)果。如果它是一個(gè)表格,最終結(jié)果就是將此表格編入索引的結(jié)果key。(這個(gè)索引是規(guī)則的,不是原始的,因此可以觸發(fā)另一個(gè)元方法。)

  • __newindex:索引分配table[key] = value。和索引事件一樣,這個(gè)事件發(fā)生在table不是表格或者key不存在時(shí)table。metamethod被抬頭table。與索引一樣,此事件的元方法可以是函數(shù)也可以是表格。如果它是一個(gè)功能,它被稱為用table,key以及value作為參數(shù)。如果它是一個(gè)表,Lua會(huì)使用相同的鍵和值對(duì)此表執(zhí)行索引分配。(這個(gè)任務(wù)是規(guī)則的,不是原始的,因此可以觸發(fā)另一個(gè)元方法。)每當(dāng)有一個(gè)__newindex元方法時(shí),Lua就不執(zhí)行原語分配。(如有必要,metamethod本身可以打電話rawset來完成作業(yè)。)

  • __call:通話操作func(args)。當(dāng)Lua嘗試調(diào)用非函數(shù)值(即,func不是函數(shù))時(shí),會(huì)發(fā)生此事件。metamethod被抬頭func。如果存在,metamethod被稱為func第一個(gè)參數(shù),然后是原始調(diào)用(args)的參數(shù)。調(diào)用的所有結(jié)果都是操作的結(jié)果。(這是允許多個(gè)結(jié)果的唯一元方法。)

在將其設(shè)置為某個(gè)對(duì)象的metatable之前,將所有需要的metamethods添加到表中是一種很好的做法。特別是,__gcmetamethod只有在遵循這個(gè)順序時(shí)才起作用(見§2.5.1)。

由于metatables是常規(guī)表,因此它們可以包含任意字段,而不僅僅是上面定義的事件名稱。標(biāo)準(zhǔn)庫中的一些功能(例如tostring)使用metatables中的其他字段來實(shí)現(xiàn)自己的目的。

2.5 – Garbage Collection

Lua執(zhí)行自動(dòng)內(nèi)存管理。這意味著您不必?fù)?dān)心為新對(duì)象分配內(nèi)存或在不再需要對(duì)象時(shí)釋放內(nèi)存。Lua通過運(yùn)行垃圾回收器來自動(dòng)管理內(nèi)存以收集所有死對(duì)象(即,不再可從Lua訪問的對(duì)象)。Lua使用的所有內(nèi)存都受自動(dòng)管理:字符串,表格,用戶數(shù)據(jù),函數(shù),線程,內(nèi)部結(jié)構(gòu)等。

Lua實(shí)現(xiàn)了一個(gè)增量式標(biāo)記和掃描收集器。它使用兩個(gè)數(shù)字來控制其垃圾收集周期:垃圾收集器暫停垃圾收集器步驟乘數(shù)。兩者均以百分點(diǎn)為單位(例如,值100表示內(nèi)部值為1)。

垃圾收集器暫??刂剖占髟陂_始新循環(huán)之前等待的時(shí)間。較大的值使收集器不那么積極。小于100的值意味著收集器不會(huì)等待開始新的循環(huán)。值為200意味著收集器在開始新周期之前等待使用的總內(nèi)存翻倍。

垃圾收集器步驟乘法器控制收集器相對(duì)于內(nèi)存分配的相對(duì)速度。較大的值使收集器更具侵略性,但也會(huì)增加每個(gè)增量步驟的大小。您不應(yīng)該使用小于100的值,因?yàn)樗鼈儠?huì)使收集器太慢,并可能導(dǎo)致收集器永遠(yuǎn)不會(huì)完成一個(gè)循環(huán)。默認(rèn)值是200,這意味著收集器以內(nèi)存分配速度的“兩倍”運(yùn)行。

如果您將步驟乘數(shù)設(shè)置為非常大的數(shù)字(大于程序可以使用的最大字節(jié)數(shù)的10%),則收集器的行為就像是一個(gè)停止世界的收集器。如果您將暫停設(shè)置為200,那么收集器的行為與舊版本的Lua版本相同,每當(dāng)Lua將其內(nèi)存使用量翻倍時(shí),會(huì)執(zhí)行完整的收集。

您可以通過lua_gc在C或collectgarbageLua中調(diào)用來更改這些數(shù)字。您也可以使用這些功能直接控制收集器(例如,停止并重新啟動(dòng)它)。

2.5.1 – Garbage-Collection Metamethods

您可以為表格設(shè)置垃圾收集器元方法,并使用C API為完整的用戶數(shù)據(jù)設(shè)置(請(qǐng)參閱第2.4節(jié))。這些metamethods也被稱為finalizer。終結(jié)器允許您將Lua的垃圾回收與外部資源管理(如關(guān)閉文件,網(wǎng)絡(luò)或數(shù)據(jù)庫連接,或釋放自己的內(nèi)存)進(jìn)行協(xié)調(diào)。

對(duì)于要收集的對(duì)象(表或用戶數(shù)據(jù))進(jìn)行最終確定時(shí),您必須標(biāo)記為最終確定。在設(shè)置其元數(shù)據(jù)時(shí),您將對(duì)象標(biāo)記為最終化,并且metatable具有由字符串“ __gc” 索引的字段。請(qǐng)注意,如果您在沒有__gc字段的情況下設(shè)置了metatable ,然后在metatable中創(chuàng)建該字段,則該對(duì)象將不會(huì)標(biāo)記為最終化。

當(dāng)一個(gè)標(biāo)記的對(duì)象變成垃圾時(shí),垃圾收集器不會(huì)立即收集它。相反,Lua把它列入清單。收集完成后,Lua會(huì)瀏覽該列表。對(duì)于列表中的每個(gè)對(duì)象,它檢查對(duì)象的__gc元方法:如果它是一個(gè)函數(shù),則Lua將該對(duì)象作為其單個(gè)參數(shù)進(jìn)行調(diào)用; 如果metamethod不是函數(shù),那么Lua會(huì)忽略它。

在每個(gè)垃圾收集周期結(jié)束時(shí),以相反的順序調(diào)用對(duì)象的終結(jié)器,以便在該周期中收集的對(duì)象被標(biāo)記為最終確定; 也就是說,要被調(diào)用的第一個(gè)終結(jié)器是與程序中最后標(biāo)記的對(duì)象相關(guān)聯(lián)的終結(jié)器。每個(gè)終結(jié)器的執(zhí)行可能會(huì)在執(zhí)行常規(guī)代碼的任何時(shí)候發(fā)生。

因?yàn)樗占膶?duì)象必須仍然被終結(jié)使用,該對(duì)象(并且只能通過其可訪問的其他對(duì)象),必須復(fù)活由Lua中。通常,這種復(fù)活是暫時(shí)的,并且在下一次垃圾收集循環(huán)中釋放對(duì)象內(nèi)存。但是,如果終結(jié)器將對(duì)象存儲(chǔ)在某個(gè)全局位置(例如全局變量)中,則復(fù)活是永久的。此外,如果終結(jié)器再次將終結(jié)對(duì)象標(biāo)記為終結(jié)對(duì)象,則在下一個(gè)對(duì)象無法訪問的周期中將再次調(diào)用終結(jié)器。在任何情況下,只有在對(duì)象不可訪問且未標(biāo)記為完成的GC循環(huán)中才釋放對(duì)象內(nèi)存。

當(dāng)你關(guān)閉一個(gè)狀態(tài)時(shí)(參見lua_close),Lua調(diào)用所有標(biāo)記為最終化的對(duì)象的終結(jié)器,按照它們被標(biāo)記的相反順序。如果任何終結(jié)器在該階段標(biāo)記用于收集的對(duì)象,則這些標(biāo)記不起作用。

2.5.2 – Weak Tables

一個(gè)弱表是一個(gè)表,它的元素是弱引用。垃圾收集器忽略弱引用。換句話說,如果對(duì)象的唯一引用是弱引用,那么垃圾收集器將收集該對(duì)象。

弱表可以具有弱鍵,弱值或兩者。具有較弱值的表允許收集其值,但會(huì)阻止收集其密鑰。具有弱鍵和弱值的表格允許集合鍵和值。在任何情況下,如果收集密鑰或值,則將整個(gè)對(duì)從表中移除。桌子的弱點(diǎn)__mode由其metatable字段控制。如果該__mode字段是包含字符' k' 的字符串,則表中的鍵很弱。如果__mode包含“ v',表中的值很弱。

具有弱鍵和強(qiáng)值的表格也被稱為ephemeron表格。在ephemeron表中,只有在密鑰可達(dá)的情況下才認(rèn)為該值可訪問。特別是,如果只有一個(gè)鍵的引用通過它的值,那么這個(gè)鍵被刪除。

只有在下一個(gè)收集周期中,表中任何弱點(diǎn)的變化才會(huì)生效。特別是,如果您將弱點(diǎn)更改為更強(qiáng)大的模式,則Lua可能會(huì)在更改生效之前從該表中收集一些項(xiàng)目。

只有具有顯式構(gòu)造的對(duì)象才會(huì)從弱表中刪除。值(如數(shù)字和亮C函數(shù))不受垃圾回收處理,因此不會(huì)從弱表中刪除(除非收集其相關(guān)值)。雖然字符串需要垃圾回收,但它們沒有明確的構(gòu)造,因此不會(huì)從弱表中刪除。

復(fù)活對(duì)象(即,正在完成的對(duì)象和只能通過正在完成的對(duì)象才可訪問的對(duì)象)在弱表中具有特殊行為。在運(yùn)行終結(jié)器之前,它們將從弱值中移除,但是在運(yùn)行終結(jié)器之后,只有在下一個(gè)集合中才從弱鍵中移除它們,而這些對(duì)象實(shí)際上已被釋放。此行為允許終結(jié)器通過弱表訪問與對(duì)象關(guān)聯(lián)的屬性。

如果收集周期中的復(fù)活對(duì)象中存在弱表,那么在下一個(gè)周期之前可能無法正確清除。

2.6 – Coroutines

Lua支持協(xié)程,也稱為協(xié)作多線程。Lua中的協(xié)程表示一個(gè)獨(dú)立的執(zhí)行線程。然而,與多線程系統(tǒng)中的線程不同,協(xié)程只通過顯式調(diào)用yield函數(shù)來暫停執(zhí)行。

通過調(diào)用創(chuàng)建協(xié)程coroutine.create。它的唯一參數(shù)是一個(gè)函數(shù),它是協(xié)程的主要功能。該create函數(shù)只創(chuàng)建一個(gè)新的協(xié)程并返回一個(gè)句柄(一個(gè)線程類型的對(duì)象); 它不啟動(dòng)協(xié)程。

你通過調(diào)用來執(zhí)行協(xié)程coroutine.resume。當(dāng)您第一次調(diào)用時(shí)coroutine.resume,將第一個(gè)參數(shù)作為返回的線程傳遞coroutine.create,協(xié)程通過調(diào)用其主函數(shù)來開始執(zhí)行。傳遞給它的額外參數(shù)coroutine.resume作為參數(shù)傳遞給該函數(shù)。協(xié)程開始運(yùn)行后,它會(huì)一直運(yùn)行,直到它終止或退出。

協(xié)程可以通過兩種方式終止它的執(zhí)行:通常,當(dāng)主函數(shù)返回(顯式或隱式地,在最后一條指令之后)時(shí); 并且在異常情況下,如果存在無保護(hù)的錯(cuò)誤。在正常終止的情況下,coroutine.resume返回,再加上協(xié)程主函數(shù)返回的任何值。如果有錯(cuò)誤,則coroutine.resume返回false加錯(cuò)誤對(duì)象。

協(xié)程通過調(diào)用產(chǎn)生收益coroutine.yield。當(dāng)協(xié)程產(chǎn)生時(shí),coroutine.resume即使產(chǎn)量發(fā)生在嵌套函數(shù)調(diào)用(即,不在主函數(shù)中,而是在由主函數(shù)直接或間接調(diào)用的函數(shù)中),也立即產(chǎn)生相應(yīng)的返回。在yield的情況下,coroutine.resume也返回true,加上傳遞給它的值coroutine.yield。下一次恢復(fù)同一個(gè)協(xié)程時(shí),它會(huì)繼續(xù)執(zhí)行它的執(zhí)行點(diǎn),并調(diào)用coroutine.yield返回傳遞給它的額外參數(shù)coroutine.resume。

類似coroutine.createcoroutine.wrap功能還創(chuàng)建了一個(gè)協(xié)程,但不是返回協(xié)同程序本身,它返回一個(gè)函數(shù),調(diào)用它時(shí),恢復(fù)協(xié)程。傳遞給這個(gè)函數(shù)的任何參數(shù)都是作為額外的參數(shù)coroutine.resume。coroutine.wrap返回由coroutine.resume第一個(gè)返回的所有值(布爾錯(cuò)誤代碼)。不像coroutine.resume,coroutine.wrap不會(huì)發(fā)現(xiàn)錯(cuò)誤; 任何錯(cuò)誤都會(huì)傳播給調(diào)用者。

作為協(xié)程的工作原理的例子,請(qǐng)考慮以下代碼:

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)你運(yùn)行它時(shí),它會(huì)產(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_newthreadlua_resumelua_yield。

前の記事: 次の記事: