作者:Roberto Ierusalimschy、Luiz Henrique de Figueiredo、Waldemar Celes
版權所有 © 2020–2023 Lua.org, PUC-Rio。根據 Lua 授權條款 免費提供。
Lua 是一個功能強大、高效、輕量級、可嵌入式的指令碼語言。它支持程序式編程、物件導向編程、函數式編程、數據驅動編程和數據描述。
Lua 將簡單的程序式語法與基於關聯數組和可擴展語義的強大數據描述構造相結合。Lua 是動態類型的,通過基於寄存器的虛擬機器解釋字節碼運行,並具有具有分代垃圾收集的自動內存管理,使其非常適合配置、指令碼和快速原型開發。
Lua 被實現為一個庫,用 clean C 編寫,這是標準 C 和 C++ 的共同子集。Lua 發行版包括一個名為 lua
的主機程序,它使用 Lua 库提供完整的、獨立的 Lua 解釋器,用於交互式或批處理使用。Lua 旨在成為用於任何需要的程序的功能強大、輕量級、可嵌入式的指令碼語言,以及一種功能強大但輕量高效的獨立語言。
作為擴展語言,Lua 沒有 "主" 程序的概念:它在一個稱為 嵌入式程序 或簡單地稱為 主機 的宿主客戶端中工作。(通常,這個主機是獨立的 lua
程序。)主機程序可以調用函數來執行一段 Lua 代碼,可以讀寫 Lua 變量,還可以註冊 C 函數供 Lua 代碼調用。通過使用 C 函數,Lua 可以擴展到應對各種不同的領域,從而創建共享語法框架的定制編程語言。
Lua 是自由軟件,根據其許可證,不提供任何擔保。本手冊描述的實現可在 Lua 的官方網站 www.lua.org
上獲得。
與任何其他參考手冊一樣,本文檔有時可能比較乏味。有關 Lua 設計背後的決策的討論,請參閱 Lua 網站提供的技術文件。有關在 Lua 中編程的詳細介紹,請參閱 Roberto 的書籍 Programming in Lua。
本節描述語言的基本概念。
Lua是一種動態類型語言。這意味著變量沒有類型,只有值有。語言中沒有類型定義。所有值都具有自己的類型。
Lua中的所有值都是一等值。這意味著所有值都可以存儲在變量中,作為參數傳遞給其他函數,並作為結果返回。
Lua中有八種基本類型:nil、boolean、number、string、function、userdata、thread和table。類型nil具有一個單一值nil,其主要屬性是與任何其他值不同;它通常表示缺少有用值。類型boolean有兩個值,false和true。 nil和false都使條件為false;它們通常被稱為false值。任何其他值都使條件為true。儘管名為false,但false經常用作nil的替代品,其關鍵區別在於false在表中的行為類似於常規值,而表中的nil表示缺少鍵。
類型number表示整數和實(浮點)數,使用兩個子類型:integer和float。標準Lua使用64位整數和雙精度(64位)浮點數,但您還可以編譯Lua以使用32位整數和/或單精度(32位)浮點數。對於小型機器和嵌入式系統,具有32位整數和浮點數的選項特別有吸引力(請參見文件luaconf.h
中的宏LUA_32BITS
)。
除非另有說明,在操作整數值時,任何溢出都將環繞,根據二補數算術的通常規則(換句話說,實際結果是與整數類型的位數n模2n相等的唯一可表示的整數結果,其中n是整數類型的位數)。
Lua有關何時使用每個子類型的明確規則,但它也會根據需要自動在它們之間進行轉換(參見§3.4.3)。因此,程序員可以選擇大多忽略整數和浮點數之間的區別,或者假設完全控制每個數字的表示。
類型string表示字節的不可變序列。Lua是8位清潔的:字符串可以包含任何8位值,包括嵌入的零('\0
')。Lua也是編碼不可知的;它不對字符串的內容做任何假設。Lua中任何字符串的長度都必須適合於Lua整數。
Lua可以調用(和操作)用Lua編寫的函數和用C編寫的函數(參見§3.4.10)。兩者都由類型function表示。
提供了 userdata 类型,以允许将任意的 C 数据存储在 Lua 变量中。一个 userdata 值表示一块原始内存区域。有两种 userdata: full userdata,它是一个由 Lua 管理的内存块对象;以及 light userdata,它只是一个 C 指针值。在 Lua 中,userdata 没有预定义的操作,除了赋值和身份测试。通过使用 metatables,程序员可以为 full userdata 值定义操作(见 §2.4)。在 Lua 中不能创建或修改 userdata 值,只能通过 C API。这保证了由宿主程序和 C 库所拥有的数据的完整性。
thread 类型表示独立的执行线程,并用于实现协程(见 §2.6)。Lua 线程与操作系统线程无关。Lua 在所有系统上都支持协程,即使那些不本地支持线程的系统。
table 类型实现了关联数组,即可以将索引值设置为除了 nil 和 NaN 之外的任何 Lua 值。(NaN 是 IEEE 754 标准中使用的特殊浮点值,用于表示未定义的数值结果,比如 0/0
。)Tables 可以是 heterogeneous 的;也就是说,它们可以包含所有类型(除了 nil)的值。与值 nil 关联的任何键都不被视为表的一部分。反之,任何不是表一部分的键都有一个关联值 nil。
Tables 是 Lua 中唯一的数据结构机制;它们可以用来表示普通数组、列表、符号表、集合、记录、图、树等等。为了表示记录,Lua 使用字段名作为索引。语言通过提供 a.name
作为语法糖来支持这种表示,即 a["name"]
。在 Lua 中有几种方便的方法可以创建 tables(见 §3.4.9)。
与索引一样,table 字段的值可以是任何类型。特别地,因为函数是一等值,table 字段可以包含函数。因此,tables 也可以携带 methods(见 §3.4.11)。
Tables 的索引遵循语言中原始相等的定义。如果且仅当 i
和 j
是原始相等(即,没有元方法)时,表达式 a[i]
和 a[j]
表示相同的表元素。特别地,具有整数值的浮点数是等于其相应的整数的(例如,1.0 == 1
)。为了避免歧义,任何用作键的浮点数如果等于整数,则会转换为该整数。例如,如果写 a[2.0] = true
,那么实际插入表中的键将是整数 2
。
表格、函式、執行緒以及(完整的)使用者資料(userdata)值都是物件:變數並不實際包含這些值,只是對它們的參考。賦值、參數傳遞和函式返回總是操作對這些值的參考;這些操作並不暗示任何形式的複製。
函式庫函數type
會返回描述給定值類型的字串(參見type
)。
正如我們稍後將在§3.2和§3.3.3中進一步討論的,對自由名稱(即未綁定到任何宣告的名稱)var
的任何參考,在語法上都會被轉譯為_ENV.var
。此外,每個程式片段都在一個名為_ENV
的外部區域變數的範圍內編譯(參見§3.3.2),因此_ENV
本身在程式片段中永遠不是一個自由名稱。
儘管存在這個外部的_ENV
變數以及自由名稱的轉譯,_ENV
本身是一個完全常規的名稱。特別是,您可以使用該名稱定義新變數和參數。每個對自由名稱的參考都使用在程式中該點可見的_ENV
,遵循Lua的通常可見性規則(參見§3.5)。
任何用作_ENV
值的表格都被稱為環境。
Lua保留一個特殊的環境,稱為全域環境。此值保留在C註冊表中的特殊索引中(參見§4.3)。在Lua中,全域變數_G
以相同的值初始化。(_G
內部從不使用,因此改變其值只會影響您自己的程式碼。)
當Lua加載一個程式片段時,其_ENV
變數的默認值是全域環境(參見load
)。因此,默認情況下,Lua程式碼中的自由名稱會參考全域環境中的項目,因此它們也被稱為全域變數。此外,所有標準函式庫都在全域環境中加載,一些函式在那裡操作該環境。您可以使用load
(或loadfile
)以不同的環境加載程式片段。(在C中,您必須加載程式片段,然後更改其第一個上值的值;參見lua_setupvalue
。)
在 Lua 中,有一些操作會引發錯誤。錯誤會中斷程序的正常流程,可以通過捕獲錯誤來繼續執行。
通過調用 error
函數,Lua 代碼可以顯式引發錯誤。(此函數永遠不會返回。)
在 Lua 中捕獲錯誤,可以進行保護調用,使用 pcall
(或 xpcall
)。函數 pcall
在保護模式下調用給定的函數。當執行該函數時發生錯誤,會停止其執行,並立即返回控制到 pcall
,它返回一個狀態碼。
由於 Lua 是一種嵌入式擴展語言,Lua 代碼是由主程序中的 C 代碼調用開始運行的。(當您使用獨立的 Lua 時,lua
應用程序是主程序。)通常,此調用是受保護的;因此,當在編譯或執行 Lua 块期間發生否則未受保護的錯誤時,控制返回到主程序,它可以採取適當的措施,例如打印錯誤消息。
每當發生錯誤時,都會傳播一個錯誤對象,其中包含有關錯誤的信息。Lua 本身僅生成其錯誤對象為字符串的錯誤,但程序可能生成任何值作為錯誤對象的錯誤。 Lua 程序或其主程序負責處理這些錯誤對象。出於歷史原因,錯誤對象通常稱為錯誤消息,即使它不必是字符串。
當使用 xpcall
(或 C 中的 lua_pcall
)時,您可以提供一個消息處理程序以在發生錯誤時調用。此函數使用原始錯誤對象調用並返回一個新的錯誤對象。它在錯誤展開堆棧之前調用,因此它可以收集有關錯誤的更多信息,例如通過檢查堆棧並創建堆棧回溯。此消息處理程序仍受受保護調用保護;因此,消息處理程序內部的錯誤將再次調用消息處理程序。如果此循環持續時間過長,Lua 將中斷它並返回適當的消息。此消息處理程序僅對常規運行時錯誤調用。它不會在運行終結器或其他消息處理程序時發生記憶體分配錯誤或錯誤。
Lua 還提供了一個警告系統(請參閱 warn
)。與錯誤不同,警告不會以任何方式干擾程序執行。它們通常只向用戶生成一條消息,儘管這種行為可以從 C 中進行調整(請參閱 lua_setwarnf
)。
在 Lua 中,每個值都可以有一個元表。這個元表是一個普通的 Lua 表,它定義了原始值在某些事件下的行為。您可以通過在其元表中設置特定字段來更改值的行為的幾個方面。例如,當非數值值是加法的操作數時,Lua 會檢查值的元表字段__add
中是否有一個函數。如果找到,Lua 將調用此函數執行加法操作。
每個事件在metatable中的鍵都是以兩個底線前綴的字符串,表示事件名稱;相應的值稱為元值。對於大多數事件,元值必須是一個函數,然後稱為元方法。在前面的示例中,鍵是字符串"__add
",而元方法是執行加法的函數。除非另有說明,否則元方法實際上可以是任何可調用的值,即函數或具有__call
元方法的值。
您可以使用getmetatable
函數查詢任何值的metatable。Lua使用原始訪問(參見rawget
)查詢metatable中的元方法。
您可以使用setmetatable
函數替換表的metatable。您無法從Lua代碼更改其他類型的metatable,除非使用調試庫(第6.10節)。
表和完整的userdata具有各自的metatable,儘管多個表和userdata可以共享它們的metatable。所有其他類型的值共享每個類型的單個metatable;也就是說,所有數字共享一個metatable,所有字符串共享一個metatable,依此類推。默認情況下,值沒有metatable,但字符串庫為字符串類型設置了metatable(參見第6.4節)。
下面給出了由metatable控制的操作的詳細列表。每個事件都由其相應的鍵標識。按照慣例,Lua使用的所有metatable鍵都由兩個底線後跟小寫拉丁字母組成。
__add
: 加法(+
)操作。如果加法的任何操作數不是數字,Lua將嘗試調用元方法。它從檢查第一個操作數開始(即使它是數字);如果該操作數未定義__add
的元方法,則Lua將檢查第二個操作數。如果Lua可以找到元方法,它將使用兩個操作數作為參數調用元方法,並將調用的結果(調整為一個值)作為操作的結果。否則,如果找不到元方法,Lua將引發錯誤。
__sub
: 減法(-
)操作。行為與加法操作類似。
__mul
: 乘法(*
)操作。行為與加法操作類似。
__div
: 除法(/
)操作。行為與加法操作類似。
__mod
: 取模(%
)操作。行為與加法操作類似。
__pow
: 指數(^
)操作。行為與加法操作類似。
__unm
: 取反(一元-
)操作。行為與加法操作類似。
__idiv
: 地板除法(//
)操作。行為與加法操作類似。
__band
: 位元 AND(&
)運算。行為類似加法運算,但如果任一運算元既不是整數也不是可以強制轉換為整數的浮點數,Lua 將嘗試使用變換方法(參見 §3.4.3)。
__bor
: 位元 OR(|
)運算。行為類似位元 AND 運算。
__bxor
: 位元 XOR(二進制 ~
)運算。行為類似位元 AND 運算。
__bnot
: 位元 NOT(一元 ~
)運算。行為類似位元 AND 運算。
__shl
: 位元左移(<<
)運算。行為類似位元 AND 運算。
__shr
: 位元右移(>>
)運算。行為類似位元 AND 運算。
__concat
: 串接(..
)運算。行為類似加法運算,但如果任一運算元既不是字串也不是數字(總是可以強制轉換為字串),Lua 將嘗試使用變換方法。
__len
: 長度(#
)運算。如果物件不是字串,Lua 將嘗試使用其變換方法。如果存在變換方法,Lua 將使用物件作為參數呼叫它,呼叫結果(始終調整為一個值)將是操作的結果。如果沒有變換方法但物件是表,則 Lua 使用表的長度操作(參見 §3.4.7)。否則,Lua 將引發錯誤。
__eq
: 等於(==
)運算。行為類似加法運算,但只有在比較的值既都是表也都是完整的使用者資料且它們不是基本相等時,Lua 才會嘗試使用變換方法。呼叫結果始終轉換為布林值。
__lt
: 小於(<
)運算。行為類似加法運算,但只有在比較的值既不都是數字也不都是字串時,Lua 才會嘗試使用變換方法。此外,呼叫結果始終轉換為布林值。
__le
: 小於等於(<=
)運算。行為類似小於運算。
__index
: 索引存取操作 table[key]
。當 table
不是表或者 key
不在 table
中時發生此事件。 metavalue 在 table
的元表中查找。
此事件的 metavalue 可以是函數、表或具有 __index
metavalue 的任何值。如果是函數,則以 table
和 key
作為參數呼叫它,呼叫結果(調整為一個值)將是操作的結果。否則,最終結果是將此 metavalue 與 key
進行索引。此索引是常規索引,而不是原始索引,因此可能會觸發另一個 __index
metavalue。
__newindex
: 索引賦值 table[key] = value
。與索引事件一樣,當 table
不是表或者 key
不在 table
中時發生此事件。 metavalue 在 table
的元表中查找。
就像索引一樣,此事件的元值可以是函數、表格,或任何具有__newindex
元值的值。如果它是一個函數,則會使用table
、key
和value
作為參數進行調用。否則,Lua將使用相同的鍵和值在此元值上重複索引分配。此分配是常規的,而不是原始的,因此可能會觸發另一個__newindex
元值。
每當調用__newindex
元值時,Lua都不會執行基本的分配。如有需要,元方法本身可以調用rawset
進行分配。
__call
: 呼叫操作func(args)
。當Lua嘗試調用非函數值(即func
不是函數)時,會發生此事件。在func
中查找元方法。如果存在,則使用func
作為其第一個參數,後跟原始呼叫的參數(args
)調用元方法。呼叫的所有結果都是操作的結果。這是唯一允許多個結果的元方法。
除了上述清單外,解譯器還尊重元表中的以下鍵:__gc
(參見§2.5.3)、__close
(參見§3.3.8)、__mode
(參見§2.5.4)和__name
。(當條目__name
包含字符串時,可以由tostring
和錯誤消息使用。)
對於一元運算符(否定、長度和按位非),將計算並調用元方法,並使用虛擬的第二個操作數,與第一個相等。此額外操作數僅為簡化Lua的內部結構而存在(使這些運算符的行為類似於二元操作),並且可能在將來的版本中被刪除。對於大多數用途,此額外操作數是不相關的。
由於元表是常規表,因此它們可以包含任意字段,不僅僅是上面定義的事件名稱。標準庫中的一些函數(例如,tostring
)使用元表中的其他字段進行其自己的用途。
將所有所需的元方法添加到表中,然後將其設置為某個對象的元表是一種良好的做法。特別是,只有在遵循此順序時,__gc
元方法才能正常工作(參見§2.5.3)。將對象的元表設置為其創建後立即設置的做法也是一種良好的做法。
Lua執行自動內存管理。這意味著您不必擔心為新對象分配內存或在對象不再需要時釋放內存。Lua通過運行垃圾收集器來自動收集所有死亡對象來自動管理內存。Lua使用的所有內存都受自動管理:字符串、表、用戶數據、函數、線程、內部結構等。
當收集器能夠確定一個物件在程式的正常執行中不會再被訪問時,該物件就被認為是死的。(此處的「正常執行」不包括 finalizers(請參見 §2.5.3),也不包括使用 debug library 的操作。)請注意,收集器能夠確定一個物件已經死亡的時間可能不會與程式設計者的預期相符。唯一的保證是 Lua 不會收集可能仍然在程式的正常執行中被訪問的物件,並且它最終會收集那些從 Lua 中無法訪問的物件。(這裡的「從 Lua 中無法訪問」指的是既沒有變數也沒有其他活動物件參考該物件。)由於 Lua 不了解 C 程式碼,它永遠不會收集通過注册表(請參見 §4.3)可訪問的物件,其中包括全局環境(請參見 §2.2)。
在 Lua 中,垃圾收集器(GC)可以以兩種模式工作:增量模式和分代模式。
預設的 GC 模式和默認參數對於大多數情況都是足夠的。但是,浪費大量時間進行記憶體分配和釋放的程式可能受益於其他設置。請記住,GC 的行為在不同平台之間和不同 Lua 版本之間都是不可移植的;因此,最佳設置也是不可移植的。
您可以通過調用 lua_gc
函數在 C 中或 collectgarbage
函數在 Lua 中來更改 GC 模式和參數。您也可以使用這些函數直接控制收集器(例如,停止和重新啟動它)。
在增量模式下,每個 GC 循環以小步驟交替進行標記和掃描收集。在此模式下,收集器使用三個數字來控制其垃圾收集循環:垃圾收集器暫停、垃圾收集器步驟乘數和垃圾收集器步驟大小。
垃圾收集器暫停控制收集器在開始新循環之前等待的時間長度。當內存使用量達到前一次收集後使用量的 n% 時,收集器就開始一個新的循環。較大的值使收集器更不積極。值等於或小於 100 意味著收集器不會等待開始新循環。值為 200 意味著收集器在開始新循環之前會等待總內存使用量加倍。默認值為 200;最大值為 1000。
垃圾收集器步驟乘數控制收集器相對於內存分配的速度,即它為每 KB 分配的內存標記或掃描的元素數量。較大的值使收集器更積極,但也會增加每個增量步驟的大小。不應使用小於 100 的值,因為這使收集器變得太慢,可能導致收集器永遠無法完成循環。默認值為 100;最大值為 1000。
垃圾收集器步驟大小控制每個增量步驟的大小,具體而言,控制解譯器在執行步驟之前分配多少字節。該參數是對數的:值 n 意味著解譯器在步驟之間分配 2n 字節並在步驟期間執行等效的工作。較大的值(例如 60)使收集器成為停止-世界(非增量)收集器。默認值為 13,這意味著每次步驟約 8 KB。
在世代模式下,收集器會頻繁進行小型收集,只遍歷最近創建的對象。如果在小型收集後,記憶體的使用量仍然高於一個限制,收集器會進行一次停止世界大型收集,遍歷所有對象。世代模式使用兩個參數:小型倍增器和大型倍增器。
小型倍增器控制小型收集的頻率。對於小型倍增器x,在先前的大型收集後使用的記憶體增長x%以上時,將執行新的小型收集。例如,對於倍增器為20,當記憶體使用量比上一個大型收集後的使用量增加20%時,收集器將執行小型收集。默認值為20;最大值為200。
大型倍增器控制大型收集的頻率。對於大型倍增器x,在先前的大型收集後使用的記憶體增長x%以上時,將執行新的大型收集。例如,對於倍增器為100,當記憶體使用量比上一次收集後的使用量增加一倍時,收集器將執行大型收集。默認值為100;最大值為1000。
您可以為表和使用C API的完整用戶數據設置垃圾回收器元方法(請參見§2.4)。這些元方法稱為終結器,當垃圾回收器檢測到相應的表或用戶數據已死時調用它們。終結器允許您協調Lua的垃圾回收與外部資源管理,例如關閉文件、網絡或數據庫連接,或釋放您自己的記憶體。
為了在收集時終止一個對象(表或用戶數據),您必須對其進行標記以進行終結。當您設置對象的元表並且元表具有__gc
元方法時,您對對象進行終結標記。請注意,如果您設置了沒有__gc
字段的元表,並且稍後在元表中創建了該字段,則該對象將不會被標記為終結。
當標記對象變為死亡時,它不會立即被垃圾回收器收集。相反,Lua將其放入列表中。在收集後,Lua會遍歷該列表。對於列表中的每個對象,它都會檢查對象的__gc
元方法:如果存在,Lua將以該對象為其單個參數調用它。
在每次垃圾回收週期結束時,將以與物件標記順序相反的順序來呼叫終結者,其中包括在該週期中收集的物件;換句話說,首先被呼叫的終結者是與程式中最後被標記的物件相關聯的終結者。每個終結者的執行可能發生在常規程式碼執行的任何時間點。
因為正在收集的物件仍然必須被終結者使用,所以該物件(以及僅通過它可存取的其他物件)必須由 Lua "復活"。通常,這種復活是暫時的,並且該物件的記憶體在下一個垃圾回收週期中被釋放。但是,如果終結者將物件存儲在某個全局位置(例如,全局變量)中,那麼復活將是永久的。此外,如果終結者再次標記一個正在終結的物件進行終結,則其終結者將在下一個物件死亡的週期中再次被呼叫。在任何情況下,只有在物件死亡且未標記為終結時,才會在 GC 週期中釋放物件的記憶體。
當您關閉一個狀態時(請參見 lua_close
),Lua 將按照它們被標記的相反順序呼叫所有已標記為終結的物件的終結者。如果在該階段期間任何終結者標記物件進行收集,則這些標記將不起作用。
終結者不能產生 yield,也不能運行垃圾收集器。由於它們可能在不可預測的時間運行,因此將每個終結者限制為正確釋放其相關資源所需的最小程度是一種良好的做法。
在執行終結者時發生任何錯誤都會生成警告;錯誤不會被傳播。
一個弱引用表是其元素為弱引用的表。弱引用被垃圾收集器忽略。換句話說,如果對一個物件的唯一引用是弱引用,那麼垃圾收集器將回收該物件。
弱表可以擁有弱鍵、弱值,或兩者皆有。具有弱值的表允許收集其值,但防止收集其鍵。具有弱鍵和弱值的表允許收集鍵和值。無論如何,如果鍵或值被收集,則整個鍵值對將從表中移除。表的弱點由其元表的__mode
字段控制。如果存在這個元值,則必須是以下字符串之一:"k
",表示具有弱鍵的表;"v
",表示具有弱值的表;或"kv
",表示具有弱鍵和弱值的表。
具有弱鍵和強值的表也稱為短暫表。在短暫表中,僅當其鍵可達時,值才被視為可達。特別是,如果鍵的唯一引用來自其值,則該鍵值對將被移除。
表弱點的任何更改可能僅在下一次收集循環時生效。特別是,如果將弱點更改為更強的模式,則在更改生效之前,Lua 可能仍會收集該表中的某些項目。
僅從具有明確構造的對象中移除弱表。例如,數字和輕量級 C 函數等值不受垃圾收集的影響,因此不會從弱表中移除(除非其關聯值被收集)。雖然字符串受垃圾收集的影響,但它們沒有明確的構造,且它們的相等性是按值比較的;它們更像值而不是對象。因此,它們不會從弱表中移除。
復活對象(即,正在完成的對象和僅通過正在完成的對象訪問的對象)在弱表中具有特殊行為。在運行其終結器之前,它們會從弱值中移除,但僅在運行其終結器後的下一次收集中,當這些對象實際被釋放時,它們才會從弱鍵中移除。這種行為允許終結器通過弱表訪問與對象關聯的屬性。
如果弱表位於收集周期中的復活對象之中,則可能要等到下一個周期才能正確清除它。
Lua 支持協同程序,也稱為協同多線程。在 Lua 中,協同程序代表一個獨立的執行緒。但是,與多線程系統中的執行緒不同,協同程序僅通過明確調用 yield 函數來暫停其執行。
透過呼叫 coroutine.create
來建立一個協程。它的唯一參數是協程的主函數。 create
函數只是建立一個新的協程並回傳其句柄(一個 thread 型別的物件);它不啟動協程。
透過呼叫 coroutine.resume
來執行一個協程。當首次呼叫 coroutine.resume
,將 coroutine.create
回傳的句柄作為其第一個參數,協程會開始執行其主函數。額外傳遞給 coroutine.resume
的參數會作為該函數的參數。協程開始執行後,它會運行直到終止或 暫停。
協程可以以兩種方式終止其執行:正常終止,當其主函數返回(明確或隱式地,在最後一個指令之後);以及異常終止,如果有未受保護的錯誤。在正常終止的情況下,coroutine.resume
返回 true,以及協程主函數返回的任何值。在出現錯誤的情況下,coroutine.resume
返回 false 加上錯誤對象。在這種情況下,協程不會展開其堆疊,因此可以在錯誤後使用 debug API 檢查。
通過調用 coroutine.yield
來使協程暫停。當一個協程暫停時,相應的 coroutine.resume
立即返回,即使 yield 發生在嵌套的函數調用中(即不在主函數中,而是在由主函數直接或間接調用的函數中)。在 yield 的情況下,coroutine.resume
也返回 true,以及傳遞給 coroutine.yield
的任何值。下一次恢復相同的協程時,它會從暫停的地方繼續執行,並且調用 coroutine.yield
會返回傳遞給 coroutine.resume
的任何額外參數。
與 coroutine.create
類似,coroutine.wrap
函數也創建一個協程,但不同的是它不返回協程本身,而是返回一個函數,該函數在調用時恢復協程。傳遞給此函數的任何參數都作為額外參數傳遞給 coroutine.resume
。coroutine.wrap
返回 coroutine.resume
返回的所有值,除了第一個(布爾錯誤碼)。與 coroutine.resume
不同,coroutine.wrap
創建的函數將任何錯誤傳播給調用者。在這種情況下,該函數還會關閉協程(參見 coroutine.close
)。
作為協程工作原理的示例,請考慮以下代碼
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"))
當你運行它時,它會產生以下輸出
co-body 1 10 foo 2 main true 4 co-body r main true 11 -9 co-body x y main true 10 end main false cannot resume dead coroutine
您還可以通過C API創建和操作協程:參見函數lua_newthread
、lua_resume
和lua_yield
。
本節描述了Lua的詞彙、語法和語義。換句話說,本節描述了哪些標記是有效的,它們如何組合,以及它們的組合意味著什麼。
使用通常的擴展BNF表示法來解釋語言構造,其中 {a} 表示 0 或多個 a,而 [a] 表示可選的 a。非終端符號的顯示方式如非終端符號,關鍵字的顯示方式如 kword,其他終端符號的顯示方式如 ‘=’。 Lua的完整語法可以在本手冊末尾的§9中找到。
Lua是一種自由格式的語言。它忽略了語法元素(標記)之間的空格和註釋,除了作為兩個標記之間的定界符。在源代碼中,Lua將標準ASCII空格字符空格、換頁符、換行符、回車符、水平制表符和垂直制表符識別為空格。
名稱(也稱為標識符)在Lua中可以是任何由拉丁字母、阿拉伯-印度數字和下劃線組成的字符串,不能以數字開頭,也不能是保留字。標識符用於命名變量、表字段和標籤。
以下關鍵字是保留的,不能用作名稱
and break do else elseif end false for function goto if in local nil not or repeat return then true until while
Lua是區分大小寫的語言:and
是一個保留字,但 And
和 AND
是兩個不同的有效名稱。作為一種慣例,程序應該避免創建以下劃線開頭,後跟一個或多個大寫字母的名稱(例如 _VERSION
)。
以下字符串表示其他標記
+ - * / % ^ # & ~ | << >> // == ~= <= >= < > = ( ) { } [ ] :: ; : , . .. ...
一個短字面值字符串可以由匹配的單引號或雙引號界定,並且可以包含以下類似於C的轉義序列:'\a
'(鈴響),'\b
'(退格),'\f
'(換頁),'\n
'(換行),'\r
'(回車),'\t
'(水平制表符),'\v
'(垂直制表符),'\\
'(反斜杠),'\"
'(引號[雙引號]),和'\'
'(撇號[單引號])。反斜杠後跟著換行符將在字符串中產生一個新行。轉義序列 '\z
' 跳過後面的空格字符範圍,包括換行符;它特別適用於將長字面值字符串拆分並縮排到多行,而不將換行符和空格添加到字符串內容中。短字面值字符串不能包含未轉義的換行符,也不能包含不形成有效轉義序列的轉義。
我們可以透過其數值來指定短文字串中的任何位元組,包括嵌入的零。這可以使用逸出序列 \xXX
來完成,其中 XX 是由確切兩個十六進位位元組組成的序列,或使用逸出序列 \ddd
,其中 ddd 是由最多三個十進位位元組組成的序列。(請注意,如果十進位逸出序列後面跟著一個數字,則必須使用確切三個位元組表示。)
Unicode 字元的 UTF-8 編碼可以使用逸出序列 \u{XXX}
(必須使用括號括起來)插入到文字串中,其中 XXX 是表示字元代碼點的一個或多個十六進位位元組的序列。此代碼點可以是小於 231 的任何值。(Lua 在此處使用原始的 UTF-8 規範,該規範不限於有效的 Unicode 代碼點。)
文字串還可以使用 長格式括號 定義。我們將一個 等級為 n 的開始長括號 定義為一個開始方括號,後面跟著 n 個等號,再後面跟著另一個開始方括號。因此,等級為 0 的開始長括號寫為 [[
,等級為 1 的開始長括號寫為 [=[
,依此類推。類似地定義了一個 結束長括號;例如,等級為 4 的結束長括號寫為 ]====]
。一個 長文字串 從任何等級的開始長括號開始,到同一等級的第一個結束長括號結束。它可以包含除了同一等級的結束括號之外的任何文字。在此括號形式中的文字可以跨越多行,不解釋任何逸出序列,並忽略任何其他等級的長括號。任何類型的行結束序列(回車、換行、回車後跟隨換行,或換行後跟隨回車)都會轉換為一個簡單的換行符。當開始長括號後面緊跟換行符時,換行符不會包含在字串中。
例如,在使用ASCII的系統中(其中'a
'編碼為 97,換行編碼為 10,'1
'編碼為 49),下面的五個文字串都表示相同的字串
a = 'alo\n123"' a = "alo\n123\"" a = '\97lo\10\04923"' a = [[alo 123"]] a = [==[ alo 123"]==]
文字串中未明確受到前述規則影響的任何位元組都代表其自身。但是,Lua以文本模式打開文件進行解析,系統的文件功能可能無法處理某些控制字符。因此,將二進制數據表示為帶有非文本字符的明確轉義序列的引用文字串會更安全。
一個數字常量(或數字)可以用可選的小數部分和可選的十進制指數來寫,由字母'e
'或'E
'標記。Lua還接受十六進制常量,以0x
或0X
開頭。十六進制常量還可以接受可選的小數部分加上可選的二進制指數,由字母'p
'或'P
'標記,並以十進制表示。 (例如,0x1.fp10
表示1984,這是0x1f / 16乘以210。)
具有小數點或指數的數字常量表示浮點數;否則,如果其值適合於整數或者它是十六進制常量,則表示整數;否則(即十進制整數數字溢出),則表示浮點數。沒有基數點或指數的十六進制數字始終表示整數值;如果值溢出,它會環繞以適合有效整數。
有效整數常量的示例為
3 345 0xff 0xBEBADA
有效浮點常量的示例為
3.0 3.1416 314.16e-2 0.31416E1 34e1 0x0.1E 0xA23p-4 0X1.921FB54442D18P+1
註釋以雙短橫線(--
)開始,可以放在字符串以外的任何地方。如果--
後面的文本不是開始的長括號,該註釋為短註釋,直到行尾為止。否則,它是長註釋,直到相應的結束的長括號。
變數是存儲值的地方。Lua中有三種類型的變數:全局變數、局部變數和表字段。
單個名稱可以表示全局變數或局部變數(或函數的形式參數,這是一種特殊類型的局部變數)
var ::= Name
名稱表示識別符(參見§3.1)。
除非明確聲明為局部變量(參見§3.3.7),否則任何變量名都被假定為全局的。局部變數具有語法作用域:局部變數可以被在其作用域內定義的函數自由訪問(參見§3.5)。
在對變量的第一次賦值之前,其值為nil。
方括號用於索引表
var ::= prefixexp ‘[’ exp ‘]’
通過元表,表字段的訪問方式可以更改(參見§2.4)。
語法var.Name
只是var["Name"]
的糖衣語法
var ::= prefixexp ‘.’ Name
對全局變量x
的訪問等同於_ENV.x
。由於chunk的編譯方式,變量_ENV
本身永遠不是全局的(參見§2.2)。
Lua支持幾乎常規的語句集,類似於其他常規語言中的語句集。該集合包括塊、賦值、控制結構、函數調用和變量聲明。
區塊是一系列語句的列表,按順序執行。
block ::= {stat}
Lua 具有 空語句,允許您使用分號分隔語句、以分號開頭區塊或連續寫兩個分號。
stat ::= ‘;’
函數調用和賦值都可以以開括號開始。這種可能性導致 Lua 的語法存在歧義。考慮以下片段:
a = b + c (print or io.write)('done')
語法分析器可以以兩種方式看待這個片段。
a = b + c(print or io.write)('done') a = b + c; (print or io.write)('done')
目前的解析器總是以第一種方式看待這樣的構造,將開括號解釋為調用的參數的開始。為了避免這種歧義,最好在以括號開始的語句之前始終加上分號。
;(print or io.write)('done')
可以明確地定義區塊,以生成單個語句。
stat ::= do block end
明確的區塊對於控制變量聲明的作用域很有用。有時明確的區塊也用於在另一個區塊中間添加 return 語句(參見 §3.3.4)。
Lua 的編譯單位稱為 程式碼塊。在語法上,程式碼塊只是一個區塊。
chunk ::= block
Lua 將程式碼塊處理為具有可變數量參數的匿名函數的主體(參見 §3.4.11)。因此,程式碼塊可以定義局部變量,接收參數並返回值。此外,這樣的匿名函數被編譯為在外部局部變量 _ENV
的作用域中(參見 §2.2)。生成的函數始終將 _ENV
作為唯一的外部變量,即使它不使用該變量。
程式碼塊可以存儲在主機程序中的文件中或字符串中。要執行程式碼塊,Lua 首先會將其 加載,將程式碼塊的代碼預編譯為虛擬機器的指令,然後使用虛擬機器的解釋器執行已編譯的代碼。
程式碼塊也可以預先編譯成二進制形式;有關詳細信息,請參見程序 luac
和函數 string.dump
。源代碼和編譯形式的程序是可互換的;Lua 會自動檢測文件類型並相應地進行操作(參見 load
)。
Lua 允許多重賦值。因此,賦值的語法定義了左側的變量列表和右側的表達式列表。兩個列表中的元素用逗號分隔。
stat ::= varlist ‘=’ explist varlist ::= var {‘,’ var} explist ::= exp {‘,’ exp}
表達式請參見 §3.4。
在分配之前,值的列表被調整為變量列表的長度(參見§3.4.12)。
如果在多重賦值中既分配又讀取變量,Lua 確保所有讀取都獲取分配之前的變量值。因此,程式碼
i = 3 i, a[i] = i+1, 20
將a[3]
設置為20,不影響a[4]
,因為a[i]
中的i
在分配之前被評估(為3),然後再分配4。同樣,該行
x, y = y, x
交換x
和y
的值,以及
x, y, z = y, z, x
循環排列x
、y
和z
的值。
請注意,此保證僅涵蓋分配語句內部的語法訪問。如果在分配期間調用的函數或元方法更改變量的值,Lua 對於該訪問的順序不提供任何保證。
對全局名稱x = val
的分配等效於分配_ENV.x = val
(參見§2.2)。
通過元表可以更改對表字段和全局變量(實際上也是表字段)的分配含義(參見§2.4)。
控制結構if、while和repeat具有通常的含義和熟悉的語法
stat ::= while exp do block end stat ::= repeat block until exp stat ::= if exp then block {elseif exp then block} [else block] end
Lua 也有for語句,有兩種形式(參見§3.3.5)。
控制結構的條件表達式可以返回任何值。false和nil都為假。與nil和false不同的所有值都為真。特別是數字0和空字符串也為真。
在repeat–until循環中,內部區塊不在until關鍵字結束,而是在條件之後。因此,條件可以參考在循環區塊內聲明的局部變量。
goto語句將程序控制轉移到標籤。出於語法原因,Lua 中的標籤也被視為語句
stat ::= goto Name stat ::= label label ::= ‘::’ Name ‘::’
標籤在定義它的整個區塊中是可見的,除了在嵌套函數內部。一個 goto 可以跳轉到任何可見的標籤,只要它不進入局部變量的範圍。不應該在已經有相同名稱的標籤可見的地方聲明標籤,即使這個其他標籤是在包含的區塊中聲明的。
break 陳述終止了 while、repeat 或 for 迴圈的執行,跳過迴圈後的下一個陳述。
stat ::= break
break 結束最內層的包圍迴圈。
return 陳述用於從函數或塊(被處理為匿名函數)返回值。函數可以返回多個值,因此 return 陳述的語法是
stat ::= return [explist] [‘;’]
return 陳述只能寫在塊的最後一個陳述。如果在塊的中間需要 return,則可以使用顯式的內部塊,如慣用法 do return end
,因為現在 return 是其(內部)塊的最後一個陳述。
for 陳述有兩種形式:數值型和通用型。
數值型 for 迴圈重複執行一個程式區塊,而控制變數通過算術遞增。它具有以下語法
stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end
給定的標識符(名稱)定義了控制變數,這是一個新的變數,局部於迴圈主體(區塊)。
迴圈從一次評估三個控制表達式開始。它們的值分別被稱為初始值、限制值和步長。如果步長不存在,則默認為 1。
如果初始值和步長都是整數,則迴圈使用整數;請注意,限制值可能不是整數。否則,三個值都會轉換為浮點數,並且迴圈使用浮點數。在這種情況下要注意浮點數的精度。
初始化後,迴圈主體重複執行,控制變數的值通過算術遞增,從初始值開始,步長給出一個公共差。負步長使得一個遞減序列;步長等於零將引發錯誤。只要值小於或等於限制值(對於負步長則大於或等於),迴圈就會繼續。如果初始值已經大於限制值(或者如果步長為負則小於),則不執行主體。
對於整數迴圈,控制變數永遠不會環繞;而是在溢出的情況下結束迴圈。
您不應在迴圈中更改控制變數的值。如果您需要在迴圈之後使用它的值,請在退出迴圈之前將其賦值給另一個變數。
通用型 for 陳述適用於稱為迭代器的函數。在每次迭代中,迭代器函數被調用以生成一個新值,在新值為 nil 時停止。通用型 for 迴圈具有以下語法
stat ::= for namelist in explist do block end namelist ::= Name {‘,’ Name}
像 for 语句如下所示:
for var_1, ···, var_n in explist do body end
工作方式如下。
名称 var_i 声明循环体内的本地循环变量。其中第一个变量是 控制变量。
循环从评估 explist 开始,以产生四个值:一个 迭代器函数,一个 状态,控制变量的初始值,以及一个 结束值。
然后,在每次迭代时,Lua 调用迭代器函数并传入两个参数:状态和控制变量。然后根据多重赋值的规则将此调用的结果分配给循环变量(详见 §3.3.3)。如果控制变量变为 nil,则循环终止。否则,执行循环体并进入下一次迭代。
结束值的行为类似于待关闭变量(详见 §3.3.8),可用于在循环结束时释放资源。否则,它不会干扰循环。
在循环期间不应更改控制变量的值。
为了允许可能的副作用,函数调用可以作为语句执行
stat ::= functioncall
在这种情况下,所有返回的值都被丢弃。函数调用在 §3.4.10 中有解释。
本地变量可以在块的任何地方声明。声明可以包含初始化
stat ::= local attnamelist [‘=’ explist] attnamelist ::= Name attrib {‘,’ Name attrib}
如果存在,则初始赋值具有多重赋值的语义(详见 §3.3.3)。否则,所有变量都初始化为 nil。
每个变量名称后面可以加上属性(位于尖括号之间的名称)
attrib ::= [‘<’ Name ‘>’]
有两种可能的属性:const
,声明一个常量变量,即一个在初始化后不能被赋值的变量;和 close
,声明一个待关闭变量(详见 §3.3.8)。变量列表最多可以包含一个待关闭变量。
一个块也是一个块(详见 §3.3.2),因此本地变量可以在块之外的块中声明。
本地变量的可见性规则在 §3.5 中有解释。
待关闭变量的行为类似于常量本地变量,只是当变量超出范围时(包括正常块终止、通过 break/goto/return 退出块,或通过错误退出时),其值会被 关闭。
这里,关闭值意味着调用其 __close
元方法。在调用元方法时,将值本身作为第一个参数传递,将导致退出的错误对象(如果有)作为第二个参数传递;如果没有错误,则第二个参数为 nil。
分配给待关闭变量的值必须具有 __close
元方法或为假值。(nil 和 false 被忽略为待关闭值。)
如果多個即將關閉的變數在同一事件中退出作用域,則按它們聲明的相反順序關閉它們。
如果在運行關閉方法時出現任何錯誤,則該錯誤將像在定義變量的常規代碼中的錯誤一樣處理。錯誤發生後,其他待處理的關閉方法仍將被調用。
如果一個協程在yield後再也沒有被恢復,則一些變量可能永遠不會退出作用域,因此它們永遠不會被關閉。(這些變量是在協程內部創建的,並且在協程yield時處於作用域中。)同樣,如果一個協程以錯誤結束,它不會解開其堆棧,因此它不會關閉任何變量。在這兩種情況下,您可以使用finalizers或調用coroutine.close
來關閉變量。但是,如果協程是通過coroutine.wrap
創建的,則其相應的函數將在錯誤情況下關閉協程。
在Lua中的基本表達式如下
exp ::= prefixexp exp ::= nil | false | true exp ::= Numeral exp ::= LiteralString exp ::= functiondef exp ::= tableconstructor exp ::= ‘...’ exp ::= exp binop exp exp ::= unop exp prefixexp ::= var | functioncall | ‘(’ exp ‘)’
數字和文字字符串在§3.1中解釋; 變量在§3.2中解釋; 函数定義在§3.4.11中解釋; 函数調用在§3.4.10中解釋; 表構造在§3.4.9中解釋。 Vararg表達式,由三個點('...
')表示,只能在直接位於可變函數內部時使用; 它們在§3.4.11中解釋。
二元運算符包括算術運算符(參見§3.4.1),位運算符(參見§3.4.2),關係運算符(參見§3.4.4),邏輯運算符(參見§3.4.5),以及連接運算符(參見§3.4.6)。一元運算符包括一元減號(參見§3.4.1),一元位NOT(參見§3.4.2),一元邏輯not(參見§3.4.5),以及一元長度運算符(參見§3.4.7)。
Lua支持以下算術運算符
+
: 加法-
: 減法*
: 乘法/
: 浮點數除法//
: 取整除法%
:取餘數^
:指數運算-
:一元減號除了指數運算和浮點數除法外,算術運算符的工作方式如下:如果兩個操作數都是整數,則將在整數上執行操作,結果為整數。否則,如果兩個操作數都是數字,則將它們轉換為浮點數,根據機器的浮點算術規則進行操作(通常是IEEE 754標準),結果為浮點數。(字符串庫在算術運算中將字符串強制轉換為數字;有關詳細信息,請參見§3.4.3。)
指數運算和浮點數除法(/
)始終將其操作數轉換為浮點數,結果始終為浮點數。指數運算使用ISO C函數pow
,因此也適用於非整數指數。
地板除法(//
)是一種將商向負無窮大取整的除法,其結果是其操作數的地板。
模數被定義為向負無窮大取整(地板除法)的除法的餘數。
在整數算術中溢出的情況下,所有操作都會進行循環。
Lua支持以下位元運算符
&
:位元AND|
:位元OR~
:位元互斥OR>>
:右位移<<
:左位移~
:一元位元NOT所有位元運算都將其操作數轉換為整數(參見§3.4.3),在這些整數的所有位上執行操作,並產生一個整數。
右位移和左位移都用零填充空位。負位移向另一方向移動;絕對值等於或高於整數位數的位移導致零(因為所有位都被移出)。
Lua提供了運行時一些類型和表示之間的自動轉換。位元運算符始終將浮點操作數轉換為整數。指數運算和浮點除法始終將整數操作數轉換為浮點數。對混合數(整數和浮點數)應用的所有其他算術運算將整數操作數轉換為浮點數。C API還根據需要將整數轉換為浮點數,將浮點數轉換為整數。此外,字符串連接接受數字作為參數,而不僅僅是字符串。
在從整數轉換為浮點數時,如果整數值具有浮點數的精確表示,則該結果。否則,轉換會獲得最接近的更高或最接近的更低可表示值。這種轉換永遠不會失敗。
將浮點數轉換為整數時,會檢查浮點數是否有精確表示為整數(即,浮點數具有整數值且在整數表示範圍內)。如果是,則該表示即為結果。否則,轉換失敗。
在 Lua 中,有幾個地方在必要時將字符串強制轉換為數字。特別是,字符串庫設置了在所有算術操作中嘗試將字符串強制轉換為數字的元方法。如果轉換失敗,庫將調用另一個運算元的元方法(如果存在),否則將引發錯誤。請注意,位操作符不會執行此類型強制轉換。
不要依賴從字符串到數字的隱式強制轉換,這是一個良好的做法,因為它們並不總是應用的;特別是,"1"==1
是 false,"1"<1
將引發錯誤(參見§3.4.4)。這些強制轉換主要是為了兼容性而存在,可能在將來的語言版本中被移除。
字符串根據其語法和 Lua 語法分析器的規則轉換為整數或浮點數。字符串可能具有前導和尾隨空格以及符號。所有從字符串到數字的轉換都接受點和當前區域標記作為基數字符。 (但是,Lua 語法分析器僅接受點。)如果字符串不是有效的數字,則轉換失敗。如有必要,此第一步的結果隨後根據以前在浮點數和整數之間轉換的規則轉換為特定的數字子類型。
從數字到字符串的轉換使用一種未指定的人類可讀格式。要以任何特定的方式將數字轉換為字符串,請使用函數string.format
。
Lua 支援以下關係運算符
==
: 等於~=
: 不等於<
: 小於>
: 大於<=
: 小於或等於>=
: 大於或等於這些運算符始終產生false或true。
等於(==
)首先比較其操作數的類型。如果類型不同,則結果為false。否則,將比較操作數的值。如果字符串具有相同的字節內容,則它們相等。如果數字表示相同的數學值,則它們相等。
表、用戶數據和線程是按引用比較的:僅當它們是相同的對象時,兩個對象才被認為相等。每次創建新對象(表、用戶數據或線程)時,此新對象與任何先前存在的對象都不同。函數始終等於自身。具有任何可檢測差異(不同的行為、不同的定義)的函數始終不同。在不同時間創建但沒有可檢測差異的函數可能被分類為相等或不相等(取決於內部緩存詳情)。
您可以通過使用 __eq
元方法(參見 §2.4)來更改 Lua 比較表和用戶數據的方式。
相等比較不會將字符串轉換為數字,反之亦然。因此,"0"==0
評估為 false,而 t[0]
和 t["0"]
表示表中的不同項目。
運算符 ~=
正好是等於(==
)的否定。
排序運算符的工作原理如下。如果兩個參數都是數字,則根據它們的數值進行比較,而不考慮它們的子類型。否則,如果兩個參數都是字符串,則根據當前地域設定比較它們的值。否則,Lua 嘗試調用 __lt
或 __le
元方法(參見 §2.4)。比較 a > b
被翻譯為 b < a
,a >= b
被翻譯為 b <= a
。
根據 IEEE 754 標準,特殊值 NaN 被認為既不小於、也不等於、也不大於任何值,包括它本身。
Lua 中的邏輯運算符包括 and、or 和 not。與控制結構一樣(參見 §3.3.4),所有邏輯運算符將 false 和 nil 視為假,其他任何值都視為真。
否定運算符 not 始終返回 false 或 true。合取運算符 and 如果第一個參數是 false 或 nil,則返回其第二個參數;否則,and 返回其第二個參數。析取運算符 or 如果第一個參數與 nil 和 false 不同,則返回其第一個參數;否則,or 返回其第二個參數。合取運算符 and 和析取運算符 or 都使用短路評估;也就是說,只有在必要時才會評估第二個操作數。以下是一些示例
10 or 20 --> 10 10 or error() --> 10 nil or "a" --> "a" nil and 10 --> nil false and error() --> false false and nil --> false false or nil --> nil 10 and 20 --> 20
Lua 中的字符串串聯運算符由兩個點('..
')表示。如果兩個操作數都是字符串或數字,則數字將以未指定的格式轉換為字符串(參見 §3.4.3)。否則,將調用 __concat
元方法(參見 §2.4)。
長度運算符由一元前綴運算符 #
表示。
字串的長度是指其位元組數。(即當每個字元佔一個位元組時的通常意義)
對於表格,長度運算子返回該表格的邊界。表格
(border == 0 or t[border] ~= nil) and (t[border + 1] == nil or border == math.maxinteger)
簡而言之,邊界是表格中存在的任何正整數索引,後跟不存在的索引,再加上兩種極端情況:索引 1 缺失時的零;以及存在該索引時的整數的最大值。請注意,非正整數的鍵不會干擾邊界。
具有確切一個邊界的表格稱為序列。例如,表格{10, 20, 30, 40, 50}是一個序列,因為它只有一個邊界(5)。表格{10, 20, 30, nil, 50}有兩個邊界(3 和 5),因此它不是序列。(索引 4 上的nil稱為空洞。)表格{nil, 20, 30, nil, nil, 60, nil}有三個邊界(0、3 和 6),所以它也不是序列。表格{}是一個具有邊界 0 的序列。
當#t
返回其唯一的邊界,這對應於序列長度的直觀概念。當#t
可以返回其任何邊界。(確切的邊界取決於表格的內部表示細節,這又取決於表格是如何填充以及其非數字鍵的記憶體地址。)
表格長度的計算保證最壞情況下的時間複雜度為O(log n),其中n是表格中最大的整數鍵。
通過__len
元方法(見§2.4),程序可以修改除字串以外的任何值的長度運算符的行為。
在Lua中,運算符的優先順序遵循下表,從低到高優先順序
or and < > <= >= ~= == | ~ & << >> .. + - * / // % unary operators (not # - ~) ^
通常情況下,您可以使用括號來更改表達式的優先順序。串接('..
')和指數('^
')運算符是右結合的。所有其他二元運算符都是左結合的。
表格構造子是用於創建表格的表達式。每次評估構造子時,都會創建一個新的表格。構造子可用於創建空表或創建表並初始化其中的一些字段。構造子的一般語法是
tableconstructor ::= ‘{’ [fieldlist] ‘}’ fieldlist ::= field {fieldsep field} [fieldsep] field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp fieldsep ::= ‘,’ | ‘;’
表單的每個欄位 [exp1] = exp2
都會將一個具有鍵為 exp1
和值為 exp2
的項目添加到新表中。形式為 name = exp
的欄位等同於 ["name"] = exp
。形式為 exp
的欄位等同於 [i] = exp
,其中 i
是從 1 開始的連續整數;其他格式的欄位不會影響此計數。例如,
a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
等同於
do local t = {} t[f(1)] = g t[1] = "x" -- 1st exp t[2] = "y" -- 2nd exp t.x = 1 -- t["x"] = 1 t[3] = f(x) -- 3rd exp t[30] = 23 t[4] = 45 -- 4th exp a = t end
構造函數中賦值的順序是未定義的。(此順序僅在有重複鍵時才有意義。)
如果列表中的最後一個欄位具有形式 exp
,且該表達式是多返回值表達式,則此表達式返回的所有值都連續進入列表中(參見 §3.4.12)。
字段列表可以有一個可選的尾隨分隔符,作為機器生成代碼的方便。
在 Lua 中,函數調用的語法如下:
functioncall ::= prefixexp args
在函數調用中,首先評估 prefixexp 和 args。如果 prefixexp 的值具有類型 function,則使用給定的參數調用此函數。否則,如果存在,則調用 prefixexp 的 __call
元方法:其第一個參數是 prefixexp 的值,其後是原始調用參數(參見 §2.4)。
形式
functioncall ::= prefixexp ‘:’ Name args
可用於模擬方法。調用 v:name(args)
是 v.name(v,args)
的語法糖,只是 v
僅評估一次。
參數具有以下語法
args ::= ‘(’ [explist] ‘)’ args ::= tableconstructor args ::= LiteralString
所有參數表達式在調用之前進行評估。形式為 f{fields}
的調用是 f({fields})
的語法糖;即,參數列表是一個新的單表。形式為 f'string'
(或 f"string"
或 f[[string]]
)的調用是 f('string')
的語法糖;即,參數列表是一個單個字面字符串。
形式為 return functioncall
的調用不在要關閉的變數的範圍內,稱為 尾部呼叫。Lua 實現了 正確的尾部呼叫(或 正確的尾部遞迴):在尾部呼叫中,被調用的函數重用調用函數的堆棧條目。因此,程序可以執行的嵌套尾部呼叫數量沒有限制。但是,尾部呼叫會刪除有關調用函數的任何調試信息。請注意,尾部呼叫僅在特定語法下發生,其中 return 的參數僅有一個單一函數呼叫,並且不在任何要關閉的變數的範圍內。此語法使調用函數確切地返回所呼叫函數的返回,而不進行任何干擾操作。因此,以下示例都不是尾部呼叫
return (f(x)) -- results adjusted to 1 return 2 * f(x) -- result multiplied by 2 return x, f(x) -- additional results f(x); return -- results discarded return x or f(x) -- results adjusted to 1
函數定義的語法是
functiondef ::= function funcbody funcbody ::= ‘(’ [parlist] ‘)’ block end
以下的語法糖簡化了函數定義
stat ::= function funcname funcbody stat ::= local function Name funcbody funcname ::= Name {‘.’ Name} [‘:’ Name]
語句
function f () body end
轉換為
f = function () body end
語句
function t.a.b.c.f () body end
轉換為
t.a.b.c.f = function () body end
語句
local function f () body end
轉換為
local f; f = function () body end
而不是
local f = function () body end
(這僅在函數體中包含對 f
的引用時才有差別。)
函數定義是一個可執行的表達式,其值的類型為 function。當 Lua 預編譯一個塊時,它的所有函數體也會被預先編譯,但它們尚未創建。然後,每當 Lua 執行函數定義時,該函數就被 實例化 (或 封閉)。這個函數實例,或 閉包,是表達式的最終值。
參數充當局部變量,其初始值為參數值
parlist ::= namelist [‘,’ ‘...’] | ‘...’
當調用 Lua 函數時,它會將其參數列表調整為其參數列表的長度(參見 §3.4.12),除非該函數是一個 可變參數函數,其在參數列表的末尾使用三個點 ('...
') 來指示。可變參數函數不會調整其參數列表;相反,它會收集所有額外的參數並通過一個 變長表達式 將它們提供給函數,這個表達式也是用三個點表示。該表達式的值是所有實際額外參數的列表,類似於具有多個結果的函數(參見 §3.4.12)。
例如,考慮以下定義
function f(a, b) end function g(a, b, ...) end function r() return 1,2,3 end
然後,我們將參數映射到參數和變長表達式
CALL PARAMETERS f(3) a=3, b=nil f(3, 4) a=3, b=4 f(3, 4, 5) a=3, b=4 f(r(), 10) a=1, b=10 f(r()) a=1, b=2 g(3) a=3, b=nil, ... --> (nothing) g(3, 4) a=3, b=4, ... --> (nothing) g(3, 4, 5, 8) a=3, b=4, ... --> 5 8 g(5, r()) a=5, b=1, ... --> 2 3
使用 return 語句返回結果(參見 §3.3.4)。如果控制流到達函數的末尾而沒有遇到 return 語句,則該函數將不返回任何結果。
函數可能返回的值有一個與系統相關的限制。此限制保證大於 1000。
冒號語法用於模擬 方法,將一個隱式的額外參數 self
添加到函數中。因此,語句
function t.a.b.c:f (params) body end
是語法糖,相當於
t.a.b.c.f = function (self, params) body end
函數調用和變長表達式都可以產生多個值。這些表達式被稱為 多結果表達式。
當一個多結果表達式用作表達式列表的最後一個元素時,來自該表達式的所有結果都將添加到表達式列表產生的值列表中。請注意,一個單一表達式在期望表達式列表的地方是該(單例)列表中的最後一個表達式。
這些是 Lua 期望表達式列表的地方
return e1, e2, e3
(參見 §3.3.4)。{e1, e2, e3}
(參見 §3.4.9)。foo(e1, e2, e3)
(參見 §3.4.10)。a , b, c = e1, e2, e3
(參見 §3.3.3)。local a , b, c = e1, e2, e3
(參見§3.3.7)。for k in e1, e2, e3 do ... end
(參見§3.3.5)。在最後四種情況中,從表達式列表中的值列表必須調整到特定長度:調用非可變函數的參數個數(參見§3.4.11)、多重賦值或局部宣告中的變量個數,以及泛型for迴圈的正好四個值。 調整遵循以下規則:如果有多餘的值,則將多餘的值丟棄;如果有比所需的值更少的值,則將列表擴展為帶有nil的值。當表達式列表以多結果表達式結尾時,該表達式的所有結果在調整之前進入值列表。
當多結果表達式在列表表達式中使用但不是最後一個元素,或者在語法期望單個表達式的位置時,Lua會將該表達式的結果列表調整為一個元素。作為一個特殊情況,語法在括號表達式內期望一個單個表達式;因此,將多結果表達式加上括號會強制它產生一個結果。
我們很少需要在語法期望單個表達式的位置使用可變引數表達式。(通常,在可變部分之前添加一個常規參數並使用該參數會更簡單。)當存在這種需要時,我們建議將可變引數表達式分配給一個單變量,並在其位置使用該變量。
以下是一些多結果表達式的用法示例。在所有情況下,當構造需要“第n個結果”,且不存在該結果時,它會使用nil。
print(x, f()) -- prints x and all results from f(). print(x, (f())) -- prints x and the first result from f(). print(f(), x) -- prints the first result from f() and x. print(1 + f()) -- prints 1 added to the first result from f(). local x = ... -- x gets the first vararg argument. x,y = ... -- x gets the first vararg argument, -- y gets the second vararg argument. x,y,z = w, f() -- x gets w, y gets the first result from f(), -- z gets the second result from f(). x,y,z = f() -- x gets the first result from f(), -- y gets the second result from f(), -- z gets the third result from f(). x,y,z = f(), g() -- x gets the first result from f(), -- y gets the first result from g(), -- z gets the second result from g(). x,y,z = (f()) -- x gets the first result from f(), y and z get nil. return f() -- returns all results from f(). return x, ... -- returns x and all received vararg arguments. return x,y,f() -- returns x, y, and all results from f(). {f()} -- creates a list with all results from f(). {...} -- creates a list with all vararg arguments. {f(), 5} -- creates a list with the first result from f() and 5.
Lua是一種語法作用域的語言。區域變量的作用域從其宣告後的第一個語句開始,並持續到包含宣告的最內層塊的最後一個非空語句。 (空語句為標籤和空語句。)考慮以下示例
x = 10 -- global variable do -- new block local x = x -- new 'x', with value 10 print(x) --> 10 x = x+1 do -- another block local x = x+1 -- another 'x' print(x) --> 12 end print(x) --> 11 end print(x) --> 10 (the global one)
請注意,在像local x = x
這樣的宣告中,正在宣告的新x
尚未在範圍內,因此第二個x
指的是外部變數。
由於詞彙範圍規則,局部變數可以被其範圍內定義的函數自由訪問。內部函數使用的局部變數在內部函數中稱為upvalue(或外部局部變數,或簡單地說是外部變數)。
請注意,每次執行local語句都會定義新的局部變數。請考慮以下示例:
a = {} local x = 20 for i = 1, 10 do local y = 0 a[i] = function () y = y + 1; return x + y end end
該循環創建十個閉包(即十個匿名函數的實例)。這些閉包中的每一個都使用不同的y
變數,而它們全部共享同一個x
。
本節描述了Lua的C API,即主機程序與Lua通信所使用的一組C 函數。所有API函數及相關類型和常量均在標頭文件lua.h
中聲明。
即使我們使用術語"函數",API中的任何功能都可以提供為宏。除非另有說明,否則所有此類宏都正好使用其每個參數一次(除第一個參數外,它總是Lua狀態),因此不會生成任何隱藏的副作用。
與大多數C 庫一樣,Lua API函數不會檢查其參數的有效性或一致性。但是,您可以通過定義宏LUA_USE_APICHECK
來更改此行為。
Lua庫是完全可重入的:它沒有全局變量。它將其所需的所有信息保存在一個名為Lua狀態的動態結構中。
每個Lua狀態都有一個或多個線程,對應於獨立的、協同的執行線。類型lua_State
(儘管其名稱如此)是指一個線程。(間接地,通過線程,它也指向與該線程關聯的Lua狀態。)
必須將指向線程的指針作為庫中每個函數的第一個參數傳遞,除了lua_newstate
之外。它從頭開始創建Lua狀態並返回指向新狀態中的主線程的指針。
Lua使用一個虛擬堆疊來將值傳遞給C,並從C獲取值。此堆疊中的每個元素代表一個Lua值(nil、數字、字符串等)。API中的函數可以通過它們接收到的Lua狀態參數訪問此堆疊。
每當Lua調用C時,被調用的函數都會獲得一個新的堆疊,該堆疊獨立於先前的堆疊以及仍然處於活動狀態的C函數的堆疊。此堆疊最初包含C函數的任何參數,它是C函數可以存儲臨時Lua值並必須將其結果推送給調用者的位置(參見lua_CFunction
)。
為了方便起見,API中的大多數查詢操作都不遵循嚴格的堆疊紀律。相反,它們可以通過使用索引來引用堆疊中的任何元素:正索引表示絕對堆疊位置,從堆疊底部的1開始;負索引表示相對於堆疊頂部的偏移。更具體地說,如果堆疊有n個元素,則索引1表示第一個元素(即最先推送到堆疊上的元素),索引n表示最後一個元素;索引-1也表示最後一個元素(即頂部的元素),索引-n表示第一個元素。
當您與 Lua API 進行交互時,您需要確保一致性。特別是,您需要負責控制堆疊溢出。當您調用任何 API 函數時,您必須確保堆疊有足夠的空間來容納結果。
上述規則有一個例外:當您調用一個 Lua 函數並且結果數量不固定時(參見 lua_call
),Lua 會確保堆疊有足夠的空間來存儲所有結果。但是,它不會確保任何額外的空間。因此,在此類調用之後往堆疊上推送任何內容之前,您應該使用 lua_checkstack
。
每當 Lua 調用 C 函數時,它都會確保堆疊至少有足夠的空間來容納 LUA_MINSTACK
個額外元素;也就是說,您可以安全地將最多 LUA_MINSTACK
個值推送到其中。 LUA_MINSTACK
被定義為 20,因此通常情況下您不需要擔心堆疊空間,除非您的代碼中有循環將元素推送到堆疊上。必要時,您可以使用函數 lua_checkstack
來確保堆疊有足夠的空間來推送新元素。
API 中接收堆疊索引的任何函數僅與有效索引或可接受索引一起使用。
有效索引是指引用可修改的 Lua 值的位置的索引。它包括堆疊索引介於 1 和堆疊頂部之間的位置(1 ≤ abs(index) ≤ top
)以及虛擬索引,虛擬索引用於訪問 C 代碼可以訪問但不在堆疊中的某些位置。虛擬索引用於訪問寄存器(參見 §4.3)和 C 函數的上值(參見 §4.2)。
不需要特定可變位置,只需要值(例如,查詢函數)的函數可以使用可接受的索引調用。一個 可接受的索引 可以是任何有效的索引,但也可以是堆疊中的堆疊頂端之後的任何正索引,即堆疊分配的空間內,也就是說,索引直到堆疊大小。(請注意,0從不是一個可接受的索引。)大於當前C函數中實際上值的upvalue數量的索引(見§4.2)也是可以接受的(但無效的)。除非另有說明,API中的函數都與可接受的索引一起工作。
可接受的索引可用於在查詢堆疊時避免對堆疊頂部進行額外測試。例如,C函數可以查詢其第三個參數,而無需檢查是否存在第三個參數,也就是說,無需檢查3是否是有效索引。
對於可以使用可接受索引調用的函數,任何非有效索引都被視為包含虛擬類型LUA_TNONE
的值,其行為類似於nil值。
API中的幾個函數返回指向堆疊中Lua字符串的指針(const char*
)。(參見lua_pushfstring
,lua_pushlstring
,lua_pushstring
和lua_tolstring
。另請參見輔助庫中的luaL_checklstring
,luaL_checkstring
和luaL_tolstring
。)
一般來說,Lua的垃圾回收可以釋放或移動內部內存,然後使內部字符串的指針無效。為了允許對這些指針的安全使用,API保證堆疊索引中字符串值未從堆疊中移除時,對字符串的指針是有效的。(它可以移動到另一個索引,但是當索引是虛擬索引(指向upvalue)時,該指針是有效的,只要相應的調用是活動的且相應的upvalue未被修改。)
調試界面中的某些功能還返回字符串指針,即 lua_getlocal
、lua_getupvalue
、lua_setlocal
和 lua_setupvalue
。對於這些功能,只要調用函數處於活動狀態,且給定的閉包(如果有的話)在堆疊中,指針就是有效的。
除了這些保證外,垃圾收集器可以無需受限制地使內部字符串的任何指針無效。
當創建 C 函數時,可以將一些值與之關聯,從而創建一個 C 闭包(參見 lua_pushcclosure
);這些值稱為 upvalues,並且在每次調用函數時都可以訪問。
每次調用 C 函數時,其 upvalues 都位於特定的虛擬索引上。這些虛擬索引由宏 lua_upvalueindex
生成。與函數關聯的第一個 upvalue 位於索引 lua_upvalueindex(1)
,依此類推。對於 lua_upvalueindex(n)
的任何訪問,其中 n 大於當前函數的 upvalues 數量(但不大於 256,這是一個閉包中最大 upvalues 數量加一)時,將生成一個可接受但無效的索引。
C 闭包還可以更改其對應 upvalues 的值。
Lua 提供了一個 註冊表,這是一個預定義的表,可供任何 C 代碼使用來存儲其需要存儲的任何 Lua 值。註冊表始終在虛擬索引 LUA_REGISTRYINDEX
上訪問。任何 C 函數庫都可以將數據存儲到該表中,但必須注意選擇與其他函數庫使用的鍵不同的鍵,以避免衝突。通常,您應該使用包含您庫名稱的字符串作為鍵,或者使用包含代碼中 C 對象地址的輕量級用戶數據,或者使用您代碼創建的任何 Lua 對象。與變量名類似,以下劃線開頭並後跟大寫字母的字符串鍵保留給 Lua 使用。
註冊表中的整數鍵由引用機制(參見 luaL_ref
)和一些預定義值使用。因此,註冊表中的整數鍵不能用於其他目的。
創建新 Lua 狀態時,其註冊表帶有一些預定義值。這些預定義值使用 lua.h
中定義的常量進行索引。定義了以下常量
LUA_RIDX_MAINTHREAD
: 在此索引處,註冊表擁有狀態的主線程。(主線程是與狀態一起創建的線程。)
LUA_RIDX_GLOBALS
: 在此索引處,註冊表擁有全局環境。
在內部,Lua 使用 C 的 longjmp
設施來處理錯誤(如果您將其編譯為 C++,Lua 將使用異常,請在源代碼中搜索 LUAI_THROW
以了解詳細信息)。當 Lua 遇到任何錯誤,如內存分配錯誤或類型錯誤時,它會引發一個錯誤;也就是說,它會進行一次長跳轉。一個 受保護的環境 使用 setjmp
來設置一個恢復點;任何錯誤都會跳轉到最近的活動恢復點。
在 C 函數內部,您可以通過調用 lua_error
來顯式引發錯誤。
API 中的大多數函數都可以引發錯誤,例如由於內存分配錯誤。每個函數的文檔都會指示它是否可以引發錯誤。
如果錯誤發生在任何受保護的環境之外,Lua 將調用一個 恐慌函數(參見 lua_atpanic
),然後調用 abort
,從而退出主機應用程序。您的恐慌函數可以通過永遠不返回(例如,對您自己在 Lua 之外的恢復點進行長跳轉)來避免此退出。
恐慌函數,如其名所示,是最後的手段。程序應該避免使用它。作為一個一般規則,當 Lua 通過 Lua 狀態調用 C 函數時,它可以在該 Lua 狀態上做任何它想做的事情,因為它應該已經受到保護。然而,當 C 代碼操作其他 Lua 狀態時(例如,作為函數的 Lua 狀態參數,存儲在註冊表中的 Lua 狀態,或者 lua_newthread
的結果),它應該僅在無法引發錯誤的 API 調用中使用它們。
恐慌函數運行時,就好像它是一個消息處理程序一樣(參見 §2.3);特別是,錯誤對象位於堆棧的頂部。但是,堆棧空間沒有保證。要將任何內容推送到堆棧上,恐慌函數必須首先檢查可用空間(參見 §4.1.1)。
在 API 中報告錯誤的幾個函數使用以下狀態碼來指示不同類型的錯誤或其他條件
LUA_OK
(0): 沒有錯誤。LUA_ERRRUN
: 執行時錯誤。LUA_ERRMEM
: 內存分配錯誤。對於此類錯誤,Lua 不會調用消息處理程序。
LUA_ERRERR
: 執行訊息處理器時發生錯誤。LUA_ERRSYNTAX
: 預編譯期間語法錯誤。LUA_YIELD
: 线程(协程)被挂起。LUA_ERRFILE
: 文件相關錯誤;例如,無法打開或讀取文件。
這些常數定義在標頭文件lua.h
中。
在內部,Lua 使用 C 的longjmp
功能來挂起協程。因此,如果 C 函數 foo
調用了一個 API 函數,而此 API 函數發生挂起(直接或間接通過調用另一個發生挂起的函數),Lua 就無法再返回到 foo
,因為 longjmp
會從 C 堆棧中移除其框架。
為避免這種問題,Lua 在試圖跨 API 調用進行挂起時引發錯誤,除了三個函數之外:lua_yieldk
、lua_callk
和lua_pcallk
。所有這些函數都接收一個繼續函數(作為名為k
的參數)來在挂起後繼續執行。
我們需要設置一些術語來解釋繼續。我們有一個從 Lua 調用的 C 函數,我們將其稱為原始函數。然後,這個原始函數調用 C API 中的其中一個函數,我們將其稱為被調用函數,然後這個被調用函數挂起了當前線程。當被調用函數是lua_yieldk
時,或者當被調用函數是lua_callk
或lua_pcallk
,並且由它們調用的函數挂起時,這種情況就會發生。
假設運行的線程在執行被調用函數時被挂起。線程恢復後,它最終將完成執行被調用函數。但是,被調用函數無法返回到原始函數,因為其在 C 堆棧中的框架已被挂起摧毀。相反,Lua 調用一個繼續函數,這個繼續函數被作為參數給被調用函數。正如其名稱所暗示的,繼續函數應該繼續原始函數的任務。
舉例來說,考慮下面的函數
int original_function (lua_State *L) { ... /* code 1 */ status = lua_pcall(L, n, m, h); /* calls Lua */ ... /* code 2 */ }
現在我們想允許由lua_pcall
運行的 Lua 代碼挂起。首先,我們可以像這樣重寫我們的函數
int k (lua_State *L, int status, lua_KContext ctx) { ... /* code 2 */ } int original_function (lua_State *L) { ... /* code 1 */ return k(L, lua_pcall(L, n, m, h), ctx); }
在上面的代碼中,新函數k
是一個繼續函數(類型為lua_KFunction
),應該執行調用lua_pcall
後原始函數要做的所有工作。現在,我們必須告訴 Lua,如果lua_pcall
執行的 Lua 代碼以某種方式被中斷(錯誤或挂起),它必須調用k
,所以我們重寫代碼如下,用lua_pcallk
替換lua_pcall
int original_function (lua_State *L) { ... /* code 1 */ return k(L, lua_pcallk(L, n, m, h, ctx2, k), ctx1); }
注意對繼續函數的外部、明確調用:只有在需要時,Lua 才會調用繼續函數,即在發生錯誤或在恢復 yield 後。如果被調用的函數正常返回而從未進行 yield,lua_pcallk
(和lua_callk
)也將正常返回。(當然,你也可以在這種情況下直接在原始函數內部進行等價的工作,而不是調用繼續函數。)
除了 Lua 狀態外,繼續函數還有兩個其他參數:調用的最終狀態和原始傳遞給lua_pcallk
的上下文值(ctx
)。Lua 不使用此上下文值;它只是將此值從原始函數傳遞給繼續函數。對於lua_pcallk
,狀態與lua_pcallk
返回的相同值相同,只是在 yield 後執行時是LUA_YIELD
(而不是LUA_OK
)。對於lua_yieldk
和lua_callk
,當 Lua 調用繼續函數時,狀態始終是LUA_YIELD
。(對於這兩個函數,Lua 不會在出錯時調用繼續函數,因為它們不處理錯誤。)同樣地,當使用lua_callk
時,你應該將繼續函數的狀態設置為LUA_OK
。(對於lua_yieldk
,直接調用繼續函數沒有太多意義,因為lua_yieldk
通常不會返回。)
Lua 將繼續函數視為原始函數。繼續函數接收來自原始函數的相同 Lua 堆棧,處於相同的狀態,就好像被調用的函數已返回一樣。(例如,在lua_callk
後,函數及其參數從堆棧中移除,並被調用結果替換。)它也擁有相同的上值。無論它返回什麼,Lua 都會將其視為原始函數的返回值。
這裡我們按字母順序列出 C API 中的所有函數和類型。每個函數都有一個類似這樣的指示器:[-o, +p, x]
第一個字段,o
,是函數從堆棧中彈出的元素數量。第二個字段,p
,是函數壓入堆棧的元素數量。(任何函數在彈出其參數後始終會將其結果壓入堆棧。)形式為x|y
的字段表示函數可以壓入(或彈出)x
或y
個元素,具體取決於情況;問號'?
'表示僅通過觀察其參數無法知道函數彈出/壓入多少個元素。(例如,它們可能取決於堆棧中的內容。)第三個字段,x
,告訴函數是否可能引發錯誤:'-
'表示函數永遠不會引發任何錯誤;'m
'表示函數可能僅引發內存不足錯誤;'v
'表示函數可能引發文本中解釋的錯誤;'e
'表示函數可以執行任意 Lua 代碼,直接或通過元方法,因此可能引發任何錯誤。
lua_absindex
[-0, +0, –]
int lua_absindex (lua_State *L, int idx);
將可接受的索引idx
轉換為等效的絕對索引(即不依賴於堆疊大小的索引)。
lua_Alloc
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
Lua 狀態使用的記憶體分配函數的類型。分配器函數必須提供類似於realloc
的功能,但不完全相同。它的參數包括ud
,即傳遞給lua_newstate
的不透明指標;ptr
,指向被分配/重新分配/釋放的區塊的指標;osize
,區塊的原始大小或有關正在分配的內容的一些代碼;以及nsize
,區塊的新大小。
當ptr
不為NULL
時,osize
是由ptr
指向的區塊的大小,即分配或重新分配時給定的大小。
當ptr
為NULL
時,osize
編碼了Lua正在分配的對象的類型。當(且僅當)Lua正在創建該類型的新對象時,osize
可以是LUA_TSTRING
、LUA_TTABLE
、LUA_TFUNCTION
、LUA_TUSERDATA
或LUA_TTHREAD
中的任何一個。當osize
是其他值時,Lua正在為其他內容分配記憶體。
Lua假定分配器函數具有以下行為
當nsize
為零時,分配器必須像free
一樣行為,然後返回NULL
。
當nsize
不為零時,分配器必須像realloc
一樣行為。特別是,如果無法滿足請求,則分配器返回NULL
。
這是分配器函數的簡單實現。它在輔助庫中由luaL_newstate
使用。
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { (void)ud; (void)osize; /* not used */ if (nsize == 0) { free(ptr); return NULL; } else return realloc(ptr, nsize); }
請注意,ISO C確保free(NULL)
不起作用,並且realloc(NULL,size)
等效於malloc(size)
。
lua_arith
[-(2|1),+1,e]
void lua_arith (lua_State *L, int op);
對堆疊頂部的兩個值(在否定情況下,僅有一個值)執行算術或位操作,其中頂部的值為第二個操作數,彈出這些值,並推送操作的結果。該函數遵循相應的Lua運算符的語義(即,它可能調用元方法)。
op
的值必須是以下常數之一
LUA_OPADD
:執行加法(+
)LUA_OPSUB
:執行減法(-
)LUA_OPMUL
:執行乘法(*
)LUA_OPDIV
:執行浮點除法(/
)LUA_OPIDIV
:執行地板除法(//
)LUA_OPMOD
:執行取餘數(%
)LUA_OPPOW
:執行指數運算(^
)LUA_OPUNM
:執行數學取反(一元 -
)LUA_OPBNOT
:執行位元取反(~
)LUA_OPBAND
:執行位元 AND(&
)LUA_OPBOR
:執行位元 OR(|
)LUA_OPBXOR
:執行位元 XOR(~
)LUA_OPSHL
:執行左位移(<<
)LUA_OPSHR
:執行右位移(>>
)lua_atpanic
[-0, +0, –]
lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
設置新的異常處理函數並返回舊函數(參見第4.4節)。
lua_call
[-(nargs+1),+nresults,e]
void lua_call (lua_State *L, int nargs, int nresults);
調用函數。與常規的 Lua 調用類似,lua_call
尊重 __call
元方法。因此,這裡的 "函數" 指的是任何可調用值。
要進行調用,必須使用以下協議:首先,將要調用的函數壓入堆棧;然後,按照直接順序壓入調用的參數;也就是說,第一個參數先壓入。最後調用lua_call
;nargs
是您壓入堆棧的參數數量。當函數返回時,將彈出所有參數和函數值,並將調用結果壓入堆棧。結果數量調整為 nresults
,除非 nresults
是LUA_MULTRET
。在這種情況下,將推送函數的所有結果;Lua 會確保返回值符合堆棧空間,但不會確保堆棧中的額外空間。將函數結果按直接順序(第一個結果先壓入)推送到堆棧上,因此在調用後,最後一個結果位於堆棧的頂部。
調用和運行函數時發生的任何錯誤都會向上傳播(使用 longjmp
)。
下面的示例顯示了主機程序如何執行與此 Lua 代碼等效的操作
a = f("how", t.x, 14)
在這裡是 C 版本
lua_getglobal(L, "f"); /* function to be called */ lua_pushliteral(L, "how"); /* 1st argument */ lua_getglobal(L, "t"); /* table to be indexed */ lua_getfield(L, -1, "x"); /* push result of t.x (2nd arg) */ lua_remove(L, -2); /* remove 't' from the stack */ lua_pushinteger(L, 14); /* 3rd argument */ lua_call(L, 3, 1); /* call 'f' with 3 arguments and 1 result */ lua_setglobal(L, "a"); /* set global 'a' */
請注意,上面的代碼是平衡的:在其結束時,堆棧恢復到其原始配置。這被認為是良好的編程實踐。
lua_callk
[-(nargs + 1),+nresults,e]
void lua_callk (lua_State *L, int nargs, int nresults, lua_KContext ctx, lua_KFunction k);
此函數的行為與 lua_call
完全相同,但允許調用的函數進行中斷(參見第4.5節)。
lua_CFunction
typedef int (*lua_CFunction) (lua_State *L);
C 函數的類型。
為了與 Lua 正確通信,C 函數必須使用以下協議,定義參數和結果傳遞的方式:C 函數在其堆疊中按直接順序從 Lua 接收其參數(第一個參數首先被推送)。因此,當函數開始時,lua_gettop(L)
將返回函數接收到的參數數量。第一個參數(如果有)位於索引 1,最後一個參數位於索引 lua_gettop(L)
。要將值返回給 Lua,C 函數只需按直接順序將它們推送到堆疊中(第一個結果首先被推送),並在 C 中返回結果的數量。堆疊中結果下方的任何其他值將被 Lua 正確丟棄。像 Lua 函數一樣,Lua 調用的 C 函數也可以返回多個結果。
例如,以下函數接收可變數量的數值參數,並返回它們的平均值和總和
static int foo (lua_State *L) { int n = lua_gettop(L); /* number of arguments */ lua_Number sum = 0.0; int i; for (i = 1; i <= n; i++) { if (!lua_isnumber(L, i)) { lua_pushliteral(L, "incorrect argument"); lua_error(L); } sum += lua_tonumber(L, i); } lua_pushnumber(L, sum/n); /* first result */ lua_pushnumber(L, sum); /* second result */ return 2; /* number of results */ }
lua_checkstack
[-0, +0, –]
int lua_checkstack (lua_State *L, int n);
確保堆疊至少有空間來容納 n
個額外元素,也就是說,您可以安全地將最多 n
個值推送到其中。如果無法滿足請求,則返回 false,原因可能是它會使堆疊大於固定的最大大小(通常至少為數千個元素)或者因為無法為額外的空間分配內存。此函數永遠不會縮小堆疊;如果堆疊已經有了額外元素的空間,則它將保持不變。
lua_close
[-0, +0, –]
void lua_close (lua_State *L);
關閉主線程中的所有活動待關閉變量,釋放給定 Lua 狀態中的所有對象(調用相應的垃圾收集元方法,如果有的話),並釋放此狀態使用的所有動態內存。
在某些平台上,您可能不需要調用此函數,因為當主機程序結束時,所有資源都會自然釋放。另一方面,創建多個狀態的長時間運行程序,例如守護程序或 Web 伺服器,可能需要在不再需要時立即關閉狀態。
lua_closeslot
[-0,+0,e]
void lua_closeslot (lua_State *L, int index);
關閉給定索引處的待關閉槽並將其值設置為 nil。索引必須是先前標記為待關閉(參見 lua_toclose
)且仍處於活動狀態(尚未關閉)的最後一個索引。
通過此函數調用時,__close
元方法無法產生結果。
(此函數於 release 5.4.3 中引入。)
lua_closethread
[-0, +?, –]
int lua_closethread (lua_State *L, lua_State *from);
重置一個線程,清理其呼叫堆疊並關閉所有待關閉的變數。返回狀態碼:LUA_OK
表示線程中沒有錯誤(無論是停止線程的原始錯誤還是關閉方法中的錯誤),否則返回錯誤狀態。在出錯情況下,會將錯誤對象留在堆疊的頂部。
參數from
表示正在重置L
的協程。如果沒有這樣的協程,則此參數可以是NULL
。
(此函數於版本5.4.6中引入。)
lua_compare
[-0,+0,e]
int lua_compare (lua_State *L, int index1, int index2, int op);
比較兩個 Lua 值。如果索引index1
處的值滿足使用索引index2
處的值進行比較時的op
,則返回1,遵循相應 Lua 運算符的語義(即,它可能調用元方法)。否則返回0。如果任何索引無效,也返回0。
op
的值必須是以下常數之一
lua_concat
[-n, +1, e]
void lua_concat (lua_State *L, int n);
連接堆疊頂部的n
個值,將它們彈出,並將結果放在頂部。如果n
為1,則結果是堆疊上的單個值(即,函數不執行任何操作);如果n
為0,則結果是空字符串。連接按照 Lua 的通常語義進行(參見§3.4.6)。
lua_copy
[-0, +0, –]
void lua_copy (lua_State *L, int fromidx, int toidx);
將索引fromidx
處的元素複製到有效索引toidx
處,並替換該位置的值。不影響其他位置的值。
lua_createtable
[-0, +1, m]
void lua_createtable (lua_State *L, int narr, int nrec);
創建一個新的空表並將其推送到堆疊上。參數narr
是表將作為序列擁有多少元素的提示;參數nrec
是表將擁有多少其他元素的提示。Lua 可能使用這些提示來為新表預先分配內存。當您事先知道表將擁有多少元素時,此預分配可能有助於性能。否則,您可以使用函數lua_newtable
。
lua_dump
[-0, +0, –]
int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip);
將函數轉儲為二進制塊。接收堆疊頂部的 Lua 函數,並生成一個二進制塊,如果重新加載,將產生與轉儲的函數等效的函數。當它產生塊的部分時,lua_dump
會調用帶有給定data
的函數writer
(參見lua_Writer
)來將它們寫入。
如果 strip
為真,二進制表示可能不包含有關函數的所有調試信息,以節省空間。
返回的值是最後一次調用寫入器時返回的錯誤碼;0 表示沒有錯誤。
此函數不會從堆棧中彈出 Lua 函數。
lua_error
[-1, +0, v]
int lua_error (lua_State *L);
引發 Lua 錯誤,使用堆棧頂部的值作為錯誤對象。此函數執行長跳轉,因此永遠不會返回(請參見 luaL_error
)。
lua_gc
[-0, +0, –]
int lua_gc (lua_State *L, int what, ...);
控制垃圾回收器。
此函數根據參數 what
的值執行幾項任務。對於需要額外參數的選項,它們在選項之後列出。
LUA_GCCOLLECT
: 執行完整的垃圾回收循環。
LUA_GCSTOP
: 停止垃圾回收器。
LUA_GCRESTART
: 重啟垃圾回收器。
LUA_GCCOUNT
: 返回 Lua 正在使用的當前內存量(以 Kbytes 為單位)。
LUA_GCCOUNTB
: 返回 Lua 正在使用的當前內存量除以 1024 得到的餘數。
LUA_GCSTEP
(int stepsize)
: 執行垃圾回收的增量步驟,對應於分配 stepsize
Kbytes。
LUA_GCISRUNNING
: 返回一個布爾值,指示回收器是否正在運行(即未停止)。
LUA_GCINC
(int pause、int stepmul、stepsize): 將回收器更改為具有給定參數的增量模式(參見 §2.5.1)。返回先前的模式(LUA_GCGEN
或 LUA_GCINC
)。
LUA_GCGEN
(int minormul、int majormul): 將回收器更改為具有給定參數的生成模式(參見 §2.5.2)。返回先前的模式(LUA_GCGEN
或 LUA_GCINC
)。
有關這些選項的更多詳細信息,請參見 collectgarbage
。
不應由終結器調用此函數。
lua_getallocf
[-0, +0, –]
lua_Alloc lua_getallocf (lua_State *L, void **ud);
返回給定狀態的記憶分配函數。如果 ud
不是 NULL
,則當記憶分配器函數設置時,Lua 將在 *ud
中存儲給定的不透明指針。
lua_getfield
[-0, +1, e]
int lua_getfield (lua_State *L, int index, const char *k);
將給定索引處的值 t[k]
推送到堆棧上,其中 t
是給定索引處的值。與 Lua 一樣,此函數可能會觸發“index”事件的元方法(參見 §2.4)。
返回推送值的類型。
lua_getextraspace
[-0, +0, –]
void *lua_getextraspace (lua_State *L);
返回与给定 Lua 状态相关联的原始内存区域的指针。应用程序可以将此区域用于任何目的;Lua 不使用它。
每个新线程都会使用主线程的此区域的副本进行初始化。
默认情况下,此区域的大小为指向 void 的指针大小,但您可以重新编译 Lua,为此区域指定不同的大小。(参见 luaconf.h
中的 LUA_EXTRASPACE
。)
lua_getglobal
[-0, +1, e]
int lua_getglobal (lua_State *L, const char *name);
将全局变量 name
的值推送到堆栈上。返回该值的类型。
lua_geti
[-0, +1, e]
int lua_geti (lua_State *L, int index, lua_Integer i);
将 t[i]
的值推送到堆栈上,其中 t
是给定索引处的值。与 Lua 一样,此函数可能会触发 "index" 事件的元方法(请参阅 §2.4)。
返回推送值的類型。
lua_getmetatable
[-0, +(0|1), –]
int lua_getmetatable (lua_State *L, int index);
如果给定索引处的值具有元表,则函数将该元表推送到堆栈上并返回 1。否则,函数返回 0 并在堆栈上不推送任何内容。
lua_gettable
[-1, +1, e]
int lua_gettable (lua_State *L, int index);
将 t[k]
的值推送到堆栈上,其中 t
是给定索引处的值,k
是堆栈顶部的值。
此函数弹出堆栈上的键,将结果值推送到其位置。与 Lua 一样,此函数可能会触发 "index" 事件的元方法(请参阅 §2.4)。
返回推送值的類型。
lua_gettop
[-0, +0, –]
int lua_gettop (lua_State *L);
返回堆栈顶部元素的索引。由于索引从 1 开始,因此此结果等于堆栈中元素的数量;特别地,0 表示堆栈为空。
lua_getiuservalue
[-0, +1, –]
int lua_getiuservalue (lua_State *L, int index, int n);
推送与给定索引处的完整用户数据相关联的第 n
个用户值到堆栈上,并返回推送值的类型。
如果用户数据没有该值,则推送 nil 并返回 LUA_TNONE
。
lua_insert
[-1, +1, –]
void lua_insert (lua_State *L, int index);
将顶部元素移动到给定的有效索引处,将此索引上方的元素向上移动以打开空间。无法使用伪索引调用此函数,因为伪索引不是实际的堆栈位置。
lua_Integer
typedef ... lua_Integer;
Lua 中整数的类型。
默认情况下,此类型为 long long
(通常为 64 位的二进制补码整数),但可以更改为 long
或 int
(通常为 32 位的二进制补码整数)。 (请参见 luaconf.h
中的 LUA_INT_TYPE
。)
Lua 还定义了常量 LUA_MININTEGER
和 LUA_MAXINTEGER
,分别为适合该类型的最小值和最大值。
lua_isboolean
[-0, +0, –]
int lua_isboolean (lua_State *L, int index);
如果给定索引处的值是布尔值,则返回 1,否则返回 0。
lua_iscfunction
[-0, +0, –]
int lua_iscfunction (lua_State *L, int index);
如果給定索引處的值是C函數,則返回1,否則返回0。
lua_isfunction
[-0, +0, –]
int lua_isfunction (lua_State *L, int index);
如果給定索引處的值是函數(無論是C函數還是Lua函數),則返回1,否則返回0。
lua_isinteger
[-0, +0, –]
int lua_isinteger (lua_State *L, int index);
如果給定索引處的值是整數(即,該值是數字且以整數形式表示),則返回1,否則返回0。
lua_islightuserdata
[-0, +0, –]
int lua_islightuserdata (lua_State *L, int index);
如果給定索引處的值是輕量級userdata,則返回1,否則返回0。
lua_isnil
[-0, +0, –]
int lua_isnil (lua_State *L, int index);
如果給定索引處的值是 nil,則返回1,否則返回0。
lua_isnone
[-0, +0, –]
int lua_isnone (lua_State *L, int index);
如果給定索引無效,則返回1,否則返回0。
lua_isnoneornil
[-0, +0, –]
int lua_isnoneornil (lua_State *L, int index);
如果給定索引無效或該索引處的值為 nil,則返回1,否則返回0。
lua_isnumber
[-0, +0, –]
int lua_isnumber (lua_State *L, int index);
如果給定索引處的值是數字或可轉換為數字的字符串,則返回1,否則返回0。
lua_isstring
[-0, +0, –]
int lua_isstring (lua_State *L, int index);
如果給定索引處的值是字符串或數字(始終可轉換為字符串),則返回1,否則返回0。
lua_istable
[-0, +0, –]
int lua_istable (lua_State *L, int index);
如果給定索引處的值是表,則返回1,否則返回0。
lua_isthread
[-0, +0, –]
int lua_isthread (lua_State *L, int index);
如果給定索引處的值是線程,則返回1,否則返回0。
lua_isuserdata
[-0, +0, –]
int lua_isuserdata (lua_State *L, int index);
如果給定索引處的值是userdata(完整或輕量級),則返回1,否則返回0。
lua_isyieldable
[-0, +0, –]
int lua_isyieldable (lua_State *L);
如果給定協程可以進行暫停,則返回1,否則返回0。
lua_KContext
typedef ... lua_KContext;
用於繼續函數上下文的類型。它必須是數字類型。當可用時,此類型被定義為 intptr_t
,以便它也可以存儲指針。否則,它被定義為 ptrdiff_t
。
lua_KFunction
typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
用於繼續函數的類型(請參見§4.5)。
lua_len
[-0, +1, e]
void lua_len (lua_State *L, int index);
返回給定索引處值的長度。它等效於Lua中的 '#
' 運算符(請參見§3.4.7),並且可能觸發“長度”事件的元方法(請參見§2.4)。結果被壓入堆棧。
lua_load
[-0, +1, –]
int lua_load (lua_State *L, lua_Reader reader, void *data, const char *chunkname, const char *mode);
載入 Lua 片段但不執行。如果沒有錯誤,lua_load
會將編譯後的片段推送到堆疊頂部作為 Lua 函數。否則,它會推送一條錯誤訊息。
lua_load
函數使用用戶提供的 reader
函數來讀取片段(參見 lua_Reader
)。data
參數是傳遞給讀取器函數的不透明值。
chunkname
參數給片段一個名稱,該名稱用於錯誤訊息和調試信息(參見 §4.7)。
lua_load
會自動檢測片段是文本還是二進制並相應地加載它(參見程序 luac
)。字符串 mode
的作用與函數 load
中相同,但增加了 NULL
值等價於字符串 "bt
"。
lua_load
在內部使用堆疊,因此當讀取器函數返回時,堆疊必須始終保持不變。
lua_load
可以返回 LUA_OK
、LUA_ERRSYNTAX
或 LUA_ERRMEM
。該函數也可能返回由讀取函數引發的其他錯誤對應的值(參見 §4.4.1)。
如果結果函數具有上值,則其第一個上值被設置為在註冊表中索引 LUA_RIDX_GLOBALS
處存儲的全局環境的值(參見 §4.3)。在加載主要片段時,該上值將是 _ENV
變量(參見 §2.2)。其他上值初始化為 nil。
lua_newstate
[-0, +0, –]
lua_State *lua_newstate (lua_Alloc f, void *ud);
創建一個新的獨立狀態並返回其主線程。如果無法創建狀態(由於內存不足),則返回 NULL
。參數 f
是分配器函數;Lua 將通過此函數為該狀態進行所有內存分配(參見 lua_Alloc
)。第二個參數 ud
是一個不透明指針,Lua 在每次調用時將其傳遞給分配器。
lua_newtable
[-0, +1, m]
void lua_newtable (lua_State *L);
創建一個新的空表並將其壓入堆疊上。等效於 lua_createtable(L, 0, 0)
。
lua_newthread
[-0, +1, m]
lua_State *lua_newthread (lua_State *L);
創建一個新的線程,將其壓入堆疊上並返回一個指向表示此新線程的 lua_State
的指針。此函數返回的新線程與原始線程共享其全局環境,但具有獨立的執行堆棧。
線程像任何 Lua 對象一樣受到垃圾回收的影響。
lua_newuserdatauv
[-0, +1, m]
void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue);
此函數創建並將新的完整用戶數據推送到堆棧上,具有關聯的 Lua 值,稱為“用戶值”,以及與大小為size
字節的原始內存塊關聯。 (可以使用函數lua_setiuservalue
和lua_getiuservalue
來設置和讀取用戶值。)
該函數返回內存塊的地址。Lua 確保此地址在相應的用戶數據存活期間有效(參見第2.5節)。此外,如果用戶數據被標記為終結(參見第2.5.3節),則其地址至少在調用其終結器之前有效。
lua_next
[-1, +(2|0), v]
int lua_next (lua_State *L, int index);
從堆棧中彈出一個鍵,並從給定索引的表中推送一個鍵-值對,即給定鍵之後的“下一個”對。如果表中沒有更多的元素,則lua_next
返回0並且不推送任何內容。
典型的表遍歷如下:
/* table is in the stack at index 't' */ lua_pushnil(L); /* first key */ while (lua_next(L, t) != 0) { /* uses 'key' (at index -2) and 'value' (at index -1) */ printf("%s - %s\n", lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1))); /* removes 'value'; keeps 'key' for next iteration */ lua_pop(L, 1); }
在遍歷表時,除非您知道鍵實際上是字符串,否則避免直接調用lua_tolstring
。請記住,lua_tolstring
可能會更改給定索引處的值;這會混淆對lua_next
的下一次調用。
如果給定的鍵既不是nil也不在表中,則此函數可能引發錯誤。請參見函數next
以獲取在遍歷過程中修改表的注意事項。
lua_Number
typedef ... lua_Number;
Lua 中浮點數的類型。
默認情況下,此類型為double,但可以將其更改為單精度浮點數或長雙精度浮點數。(請參見luaconf.h
中的LUA_FLOAT_TYPE
。)
lua_numbertointeger
int lua_numbertointeger (lua_Number n, lua_Integer *p);
試圖將 Lua 浮點數轉換為 Lua 整數;浮點數n
必須具有整數值。如果該值在 Lua 整數的範圍內,則將其轉換為整數並分配給*p
。該宏將返回一個布爾值,指示轉換是否成功。(請注意,這個範圍測試可能很難正確執行,如果沒有這個宏,就會由於四捨五入而造成混淆。)
此宏可能對其參數進行多次評估。
lua_pcall
[-(nargs + 1), +(nresults|1), –]
int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);
以保護模式調用函數(或可調用對象)。
nargs
和nresults
的含義與lua_call
中的相同。如果在調用期間沒有錯誤,lua_pcall
的行為與lua_call
完全相同。但是,如果存在任何錯誤,lua_pcall
將捕獲它,將單個值(錯誤對象)推送到堆棧上並返回錯誤碼。與lua_call
一樣,lua_pcall
始終從堆棧上刪除函數及其參數。
如果msgh
為0,那麼返回的錯誤對象恰好是原始錯誤對象。否則,msgh
是一個消息處理器的堆棧索引。(此索引不能是虛擬索引。)在運行時錯誤的情況下,此處理器將被調用,並以錯誤對象為參數,其返回值將是lua_pcall
返回的堆棧上的對象。
通常,消息處理器用於向錯誤對象添加更多調試信息,例如堆棧回溯。此類信息在lua_pcall
返回之後無法收集,因為此時堆棧已解開。
lua_pcall
函數返回以下狀態碼之一:LUA_OK
、LUA_ERRRUN
、LUA_ERRMEM
或LUA_ERRERR
。
lua_pcallk
[-(nargs + 1), +(nresults|1), –]
int lua_pcallk (lua_State *L, int nargs, int nresults, int msgh, lua_KContext ctx, lua_KFunction k);
此函數的行為與lua_pcall
完全相同,但允許被調用的函數進行yield(參見§4.5)。
lua_pop
[-n,+0,e]
void lua_pop (lua_State *L, int n);
從堆棧中彈出n
個元素。它被實現為lua_settop
的宏。
lua_pushboolean
[-0, +1, –]
void lua_pushboolean (lua_State *L, int b);
將布爾值b
推送到堆棧上。
lua_pushcclosure
[-n,+1,m]
void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
將一個新的C閉包推送到堆棧上。此函數接收一個指向C函數的指針,並推送一個Lua值到堆棧上,類型為function
,當調用時,將調用相應的C函數。參數n
表示此函數將具有多少個上值(參見§4.2)。
任何要被Lua調用的函數都必須遵循正確的協議以接收其參數並返回其結果(參見lua_CFunction
)。
當創建一個 C 函數時,可以將一些值與其關聯起來,這些被稱為上值;每次調用函數時,這些上值將對該函數可訪問。這種關聯稱為 C 閉包(參見 §4.2)。要創建一個 C 閉包,首先必須將其上值的初始值壓入堆棧。 (當存在多個上值時,首先壓入第一個值。)然後調用 lua_pushcclosure
來創建並將 C 函數壓入堆棧,參數 n
告訴有多少值將與該函數關聯。 lua_pushcclosure
還將這些值從堆棧中彈出。
n
的最大值為 255。
當 n
為零時,此函數創建一個輕量級 C 函數,它只是指向 C 函數的指針。在這種情況下,它永遠不會引發內存錯誤。
lua_pushcfunction
[-0, +1, –]
void lua_pushcfunction (lua_State *L, lua_CFunction f);
將 C 函數壓入堆棧。此函數等效於沒有上值的 lua_pushcclosure
。
lua_pushfstring
[-0, +1, v]
const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
將格式化字符串壓入堆棧並返回指向該字符串的指針(參見 §4.1.3)。它類似於 ISO C 函数 sprintf
,但有兩個重要的區別。首先,您無需為結果分配空間;結果是一個 Lua 字符串,Lua 負責內存分配(和釋放,通過垃圾回收)。其次,轉換指定符相當受限制。沒有標誌、寬度或精度。轉換指定符只能是 '%%
'(插入字符 '%
'),'%s
'(插入以零結尾的字符串,沒有大小限制),'%f
'(插入 lua_Number
),'%I
'(插入 lua_Integer
),'%p
'(插入指針),'%d
'(插入 int),'%c
'(將 int 插入為一個字節字符),以及 '%U
'(將 long int 插入為 UTF-8 字節序列)。
此函數可能由於內存溢出或無效的轉換指定符而引發錯誤。
lua_pushglobaltable
[-0, +1, –]
void lua_pushglobaltable (lua_State *L);
將全局環境壓入堆棧。
lua_pushinteger
[-0, +1, –]
void lua_pushinteger (lua_State *L, lua_Integer n);
將值為 n
的整數壓入堆棧。
lua_pushlightuserdata
[-0, +1, –]
void lua_pushlightuserdata (lua_State *L, void *p);
將輕量級用戶數據壓入堆棧。
UserData 在 Lua 中代表 C 值。 轻量级 UserData 代表一个指针,一个 void*
。它是一个值(就像一个数字):你不需要创建它,它没有独立的元表,并且它不会被回收(因为它从未被创建)。一个轻量级 UserData 等于具有相同 C 地址的“任何”轻量级 UserData。
lua_pushliteral
[-0, +1, m]
const char *lua_pushliteral (lua_State *L, const char *s);
这个宏等同于 lua_pushstring
,但只应在 s
是字面字符串时使用。(Lua 可能会优化这种情况。)
lua_pushlstring
[-0, +1, m]
const char *lua_pushlstring (lua_State *L, const char *s, size_t len);
将由 s
指向的大小为 len
的字符串推入堆栈。Lua 将创建或重用给定字符串的内部副本,因此在函数返回后,s
处的内存可以立即被释放或重用。字符串可以包含任何二进制数据,包括嵌入的零。
返回指向字符串内部副本的指针(见 §4.1.3)。
lua_pushnil
[-0, +1, –]
void lua_pushnil (lua_State *L);
将一个 nil 值推入堆栈。
lua_pushnumber
[-0, +1, –]
void lua_pushnumber (lua_State *L, lua_Number n);
将值为 n
的浮点数推入堆栈。
lua_pushstring
[-0, +1, m]
const char *lua_pushstring (lua_State *L, const char *s);
将由 s
指向的以零结尾的字符串推入堆栈。Lua 将创建或重用给定字符串的内部副本,因此在函数返回后,s
处的内存可以立即被释放或重用。
返回指向字符串内部副本的指针(见 §4.1.3)。
如果 s
是 NULL
,则推入 nil 并返回 NULL
。
lua_pushthread
[-0, +1, –]
int lua_pushthread (lua_State *L);
将由 L
表示的线程推入堆栈。如果此线程是其状态的主线程,则返回 1。
lua_pushvalue
[-0, +1, –]
void lua_pushvalue (lua_State *L, int index);
将给定索引处的元素的副本推入堆栈。
lua_pushvfstring
[-0, +1, v]
const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);
等同于 lua_pushfstring
,不同之处在于它接收一个 va_list
而不是可变数量的参数。
lua_rawequal
[-0, +0, –]
int lua_rawequal (lua_State *L, int index1, int index2);
如果索引 index1
和 index2
处的两个值在原始情况下相等(即,不调用 __eq
元方法),则返回 1。否则返回 0。如果任何一个索引无效,也返回 0。
lua_rawget
[-1, +1, –]
int lua_rawget (lua_State *L, int index);
类似于 lua_gettable
,但是进行原始访问(即,不使用元方法)。index
处的值必须是一个表。
lua_rawgeti
[-0, +1, –]
int lua_rawgeti (lua_State *L, int index, lua_Integer n);
将给定索引处的表的值 t[n]
推入堆栈。访问是原始的,即不使用 __index
元值。
返回推送值的類型。
lua_rawgetp
[-0, +1, –]
int lua_rawgetp (lua_State *L, int index, const void *p);
將索引處的表格 t
中的值 t[k]
壓入堆疊,其中 t
為給定索引處的表格,k
為以輕量級用戶數據表示的指針 p
。此訪問是原始的,即它不使用 __index
元值。
返回推送值的類型。
lua_rawlen
[-0, +0, –]
lua_Unsigned lua_rawlen (lua_State *L, int index);
返回給定索引處值的原始“長度”:對於字符串,這是字符串的長度;對於表格,這是不使用元方法的長度運算符('#
')的結果;對於用戶數據,這是為用戶數據分配的內存塊的大小。對於其他值,此調用返回 0。
lua_rawset
[-2, +0, m]
void lua_rawset (lua_State *L, int index);
類似於 lua_settable
,但執行原始賦值(即不使用元方法)。索引
處的值必須是表格。
lua_rawseti
[-1, +0, m]
void lua_rawseti (lua_State *L, int index, lua_Integer i);
執行相當於 t[i] = v
,其中 t
為給定索引處的表格,v
為堆疊頂部的值。
此函數從堆疊中彈出值。此賦值是原始的,即它不使用 __newindex
元值。
lua_rawsetp
[-1, +0, m]
void lua_rawsetp (lua_State *L, int index, const void *p);
執行相當於 t[p] = v
,其中 t
為給定索引處的表格,p
編碼為輕量級用戶數據,v
為堆疊頂部的值。
此函數從堆疊中彈出值。此賦值是原始的,即它不使用 __newindex
元值。
lua_Reader
typedef const char * (*lua_Reader) (lua_State *L, void *data, size_t *size);
lua_load
使用的讀取器函數。每次 lua_load
需要 chunk 的另一部分時,它都會調用讀取器,並傳遞其 data
參數。讀取器必須返回指向新 chunk 一部分的內存塊的指針,並將 size
設置為該塊的大小。該塊必須存在,直到再次調用讀取器函數。要標記 chunk 的結束,讀取器必須返回 NULL
或將 size
設置為零。讀取器函數可以返回任何大於零的大小的片段。
lua_register
[-0,+0,e]
void lua_register (lua_State *L, const char *name, lua_CFunction f);
將 C 函數 f
設置為全局 name
的新值。它被定義為一個宏
#define lua_register(L,n,f) \ (lua_pushcfunction(L, f), lua_setglobal(L, n))
lua_remove
[-1, +0, –]
void lua_remove (lua_State *L, int index);
刪除給定有效索引處的元素,將該索引上面的元素向下移動以填充空隙。此函數無法使用偽索引調用,因為偽索引不是實際的堆疊位置。
lua_replace
[-1, +0, –]
void lua_replace (lua_State *L, int index);
將頂部元素移動到給定有效索引處,而不移動任何元素(因此替換該給定索引處的值),然後彈出頂部元素。
lua_resetthread
[-0, +?, –]
int lua_resetthread (lua_State *L);
此函數已廢棄;它等效於 lua_closethread
,其中 from
為 NULL
。
lua_resume
[-?, +?, –]
int lua_resume (lua_State *L, lua_State *from, int nargs, int *nresults);
在给定的线程 L
中启动和恢复一个协程。
要启动一个协程,您需要将主函数以及任何参数推入线程的空栈,然后调用 lua_resume
,其中 nargs
是参数的数量。当协程暂停或完成执行时,该调用将返回。当它返回时,*nresults
将被更新,并且栈顶包含传递给 lua_yield
的 *nresults
值或由主体函数返回的值。如果协程暂停,则 lua_resume
返回 LUA_YIELD
;如果协程在没有错误的情况下完成执行,则返回 LUA_OK
;或者在出现错误时返回错误代码(参见 §4.4.1)。在出现错误的情况下,错误对象位于栈顶。
要恢复一个协程,您需要从其栈中移除 *nresults
产生的值,将要作为结果传递给 yield
的值推入,然后调用 lua_resume
。
参数 from
表示正在恢复执行的协程 L
。如果没有这样的协程,则此参数可以是 NULL
。
lua_rotate
[-0, +0, –]
void lua_rotate (lua_State *L, int idx, int n);
在有效索引 idx
和栈顶之间旋转栈元素。元素沿着从顶部到底部的方向旋转 n
个位置,对于正 n
,或者沿着从底部到顶部的方向旋转 -n
个位置,对于负 n
。 n
的绝对值不能大于被旋转的切片的大小。此函数不能使用伪索引调用,因为伪索引不是实际的栈位置。
lua_setallocf
[-0, +0, –]
void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
将给定状态的分配器函数更改为带有用户数据 ud
的 f
。
lua_setfield
[-1, +0, e]
void lua_setfield (lua_State *L, int index, const char *k);
将 t
索引处的值设置为栈顶的值,相当于 t[k] = v
。
此函数弹出栈中的值。与 Lua 一样,此函数可能触发 "newindex" 事件的元方法(参见 §2.4)。
lua_setglobal
[-1, +0, e]
void lua_setglobal (lua_State *L, const char *name);
从栈中弹出一个值,并将其设置为全局变量 name
的新值。
lua_seti
[-1, +0, e]
void lua_seti (lua_State *L, int index, lua_Integer n);
等同於 t[n] = v
,其中 t
為給定索引處的值,v
為堆疊頂部的值。
此函数弹出栈中的值。与 Lua 一样,此函数可能触发 "newindex" 事件的元方法(参见 §2.4)。
lua_setiuservalue
[-1, +0, –]
int lua_setiuservalue (lua_State *L, int index, int n);
從堆疊中彈出一個值,並將其設置為給定索引處的完整用戶數據關聯的新的第 n
個用戶值。如果用戶數據沒有該值,則返回 0。
lua_setmetatable
[-1, +0, –]
int lua_setmetatable (lua_State *L, int index);
從堆疊中彈出一個表或 nil,並將該值設置為給定索引處的值的新元表。(nil 表示無元表。)
(出於歷史原因,此函數返回一個 int
,但現在始終為 1。)
lua_settable
[-2, +0, e]
void lua_settable (lua_State *L, int index);
等同於 t[k] = v
,其中 t
為給定索引處的值,v
為堆疊頂部的值,k
為剛好在頂部下方的值。
此函數從堆疊中彈出鍵和值。與 Lua 一樣,此函數可能觸發 "newindex" 事件的元方法(參見 §2.4)。
lua_settop
[-?, +?, e]
void lua_settop (lua_State *L, int index);
接受任何索引,或 0,並將堆疊頂部設置為此索引。如果新頂部大於舊頂部,則新元素將填充為 nil。如果 index
為 0,則將移除所有堆疊元素。
此函數可以在從堆疊中刪除標記為將被關閉的索引時運行任意代碼。
lua_setwarnf
[-0, +0, –]
void lua_setwarnf (lua_State *L, lua_WarnFunction f, void *ud);
設置 Lua 用於發出警告的警告函數(參見 lua_WarnFunction
)。參數 ud
設置為傳遞給警告函數的值 ud
。
lua_State
typedef struct lua_State lua_State;
一個指向線程的不透明結構,間接(通過線程)指向 Lua 解譯器的整個狀態。Lua 库是完全可重入的:它沒有全局變量。有關狀態的所有信息都可以通過這個結構訪問。
必須將對此結構的指針作為庫中每個函數的第一個參數傳遞,除了 lua_newstate
,它從頭開始創建一個 Lua 狀態。
lua_status
[-0, +0, –]
int lua_status (lua_State *L);
返回線程 L
的狀態。
狀態可以是一個正常線程的 LUA_OK
,如果線程完成了帶有錯誤的 lua_resume
的執行,則是錯誤碼,或者如果線程被暫停則是 LUA_YIELD
。
只能在具有狀態 LUA_OK
的線程中調用函數。可以恢復具有狀態 LUA_OK
的線程(以開始一個新的協程)或具有狀態 LUA_YIELD
的線程(以恢復協程)。
lua_stringtonumber
[-0, +1, –]
size_t lua_stringtonumber (lua_State *L, const char *s);
將以零結尾的字串 s
轉換為數字,將該數字推送到堆疊中,並返回字符串的總大小,即其長度加一。根據 Lua 的詞法約定,轉換可能產生整數或浮點數(參見§3.1)。字符串可能具有前導和尾隨的空格以及符號。如果字符串不是有效的數字,則返回0並且不推送任何內容。(注意,結果可以用作布林值,如果轉換成功則為真。)
lua_toboolean
[-0, +0, –]
int lua_toboolean (lua_State *L, int index);
將給定索引處的 Lua 值轉換為 C 布林值(0 或 1)。與 Lua 中的所有測試一樣,lua_toboolean
對於與 false 和 nil 不同的任何 Lua 值返回 true;否則返回 false。(如果您只想接受實際布林值,請使用lua_isboolean
測試值的類型。)
lua_tocfunction
[-0, +0, –]
lua_CFunction lua_tocfunction (lua_State *L, int index);
將給定索引處的值轉換為 C 函數。該值必須是 C 函數;否則,返回NULL
。
lua_toclose
[-0, +0, m]
void lua_toclose (lua_State *L, int index);
將堆疊中的給定索引標記為待關閉的插槽(參見§3.3.8)。就像在 Lua 中的待關閉變數一樣,在堆疊中的該插槽上的值在超出作用域時將被關閉。在這裡,在 C 函數的上下文中,超出作用域意味著運行的函數返回到 Lua,或者出現錯誤,或者通過lua_settop
或lua_pop
將插槽從堆疊中移除,或者調用lua_closeslot
。標記為待關閉的插槽不應由 API 中的任何其他函數除lua_settop
或lua_pop
以外的函數從堆疊中移除,除非先前由lua_closeslot
停用。
不應對等於或低於活動待關閉插槽的索引調用此函數。
請注意,在錯誤情況和常規返回的情況下,當__close
元方法運行時,C 堆疊已經被展開,因此在呼叫函數中聲明的任何自動 C 變量(例如緩衝區)將超出作用域。
lua_tointeger
[-0, +0, –]
lua_Integer lua_tointeger (lua_State *L, int index);
等同於 lua_tointegerx
,其中 isnum
等於 NULL
。
lua_tointegerx
[-0, +0, –]
lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);
將給定索引處的 Lua 值轉換為帶符號整數類型 lua_Integer
。Lua 值必須是整數,或者可以轉換為整數的數字或字符串(參見 §3.4.3);否則,lua_tointegerx
將返回 0。
如果 isnum
不是 NULL
,則將其參考分配為一個布林值,指示操作是否成功。
lua_tolstring
[-0, +0, m]
const char *lua_tolstring (lua_State *L, int index, size_t *len);
將給定索引處的 Lua 值轉換為 C 字串。如果 len
不是 NULL
,它將用字符串長度設置 *len
。Lua 值必須是字符串或數字;否則,該函數將返回 NULL
。如果該值是數字,則 lua_tolstring
還會將堆疊中的實際值更改為字符串。(當在表遍歷期間將 lua_tolstring
應用於鍵時,此更改會使 lua_next
混淆。)
lua_tolstring
返回一個指向 Lua 狀態內部的字符串的指針(參見 §4.1.3)。此字符串始終在其最後一個字符後包含一個零(' \0
'),但其內部可能包含其他零。
lua_tonumber
[-0, +0, –]
lua_Number lua_tonumber (lua_State *L, int index);
等同於 lua_tonumberx
,其中 isnum
等於 NULL
。
lua_tonumberx
[-0, +0, –]
lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);
將給定索引處的 Lua 值轉換為 C 類型 lua_Number
(參見 lua_Number
)。Lua 值必須是數字或可轉換為數字的字符串;否則,lua_tonumberx
將返回 0。
如果 isnum
不是 NULL
,則將其參考分配為一個布林值,指示操作是否成功。
lua_topointer
[-0, +0, –]
const void *lua_topointer (lua_State *L, int index);
將給定索引處的值轉換為通用的 C 指針(void*
)。該值可以是 userdata、表、線程、字符串或函數;否則,lua_topointer
將返回 NULL
。不同的對象將給出不同的指針。無法將指針轉換回其原始值。
通常,此函數僅用於哈希和調試信息。
lua_tostring
[-0, +0, m]
const char *lua_tostring (lua_State *L, int index);
等同於 lua_tolstring
,其中 len
等於 NULL
。
lua_tothread
[-0, +0, –]
lua_State *lua_tothread (lua_State *L, int index);
將給定索引處的值轉換為 Lua 线程(表示為 lua_State*
)。該值必須是一個线程;否則,函數將返回 NULL
。
lua_touserdata
[-0, +0, –]
void *lua_touserdata (lua_State *L, int index);
如果給定索引處的值是完整的使用者數據,則返回其內存塊地址。如果該值是輕量級使用者數據,則返回其值(一個指針)。否則,返回 NULL
。
lua_type
[-0, +0, –]
int lua_type (lua_State *L, int index);
返回給定有效索引處的值的類型,或者對於非有效但可接受的索引,返回 LUA_TNONE
。由 lua_type
返回的類型由 lua.h
中定義的以下常量編碼: LUA_TNIL
、LUA_TNUMBER
、LUA_TBOOLEAN
、LUA_TSTRING
、LUA_TTABLE
、LUA_TFUNCTION
、LUA_TUSERDATA
、LUA_TTHREAD
和 LUA_TLIGHTUSERDATA
。
lua_typename
[-0, +0, –]
const char *lua_typename (lua_State *L, int tp);
返回由值 tp
編碼的類型的名稱,該值必須是 lua_type
返回的值之一。
lua_Unsigned
typedef ... lua_Unsigned;
lua_Integer
的無符號版本。
lua_upvalueindex
[-0, +0, –]
int lua_upvalueindex (int i);
返回表示運行函數的第 i
個上值的虛擬索引(見 §4.2)。i
必須在範圍 [1,256] 內。
lua_version
[-0, +0, –]
lua_Number lua_version (lua_State *L);
返回此核心的版本號。
lua_WarnFunction
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
警告函數的類型,由 Lua 調用以發出警告。第一個參數是由 lua_setwarnf
設置的不透明指針。第二個參數是警告消息。第三個參數是一個布爾值,指示消息是否應在下一次調用中由下一個消息繼續。
有關警告的詳細信息,請參見 warn
。
lua_warning
[-0, +0, –]
void lua_warning (lua_State *L, const char *msg, int tocont);
發出具有給定消息的警告。在具有 tocont
為 true 的調用中的消息應在另一次對此函數的調用中繼續。
有關警告的詳細信息,請參見 warn
。
lua_Writer
typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud);
lua_dump
使用的寫入器函數的類型。每次 lua_dump
生成另一個塊時,它調用寫入器,傳遞要寫入的緩衝區(p
)、其大小(sz
)和提供給 lua_dump
的 ud
參數。
寫入器返回一個錯誤碼:0 表示無錯誤;任何其他值表示錯誤並停止 lua_dump
再次調用寫入器。
lua_xmove
[-?, +?, –]
void lua_xmove (lua_State *from, lua_State *to, int n);
在同一個狀態的不同线程之間交換值。
此函數從堆棧 from
中彈出 n
個值,並將它們推送到堆棧 to
。
lua_yield
[-?, +?, v]
int lua_yield (lua_State *L, int nresults);
此函數等效於 lua_yieldk
,但它沒有繼續(見 §4.5)。因此,當線程恢復時,它將繼續調用調用 lua_yield
的函數。為避免驚喜,此函數應僅在尾調用中調用。
lua_yieldk
[-?, +?, v]
int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, lua_KFunction k);
將一個協程(線程)暫停。
當一個 C 函數調用 lua_yieldk
時,運行中的協程暫停其執行,啟動該協程的 lua_resume
調用返回。參數 nresults
是將從堆疊中傳遞為結果到 lua_resume
的值的數量。
當協程再次被恢復時,Lua 調用給定的繼續函數 k
來繼續執行 C 函數的執行(參見 §4.5)。這個繼續函數接收到與前一個函數相同的堆疊,將 n
個結果移除並替換為傳遞給 lua_resume
的參數。此外,繼續函數接收到傳遞給 lua_yieldk
的值 ctx
。
通常,此函數不會返回;當協程最終恢復時,它將繼續執行繼續函數。然而,有一個特殊情況,即當此函數從線或計數鉤子內部被調用時(參見 §4.7)。在這種情況下,應該使用沒有繼續(可能以 lua_yield
的形式)和沒有結果來調用 lua_yieldk
,並且鉤子應該在調用後立即返回。Lua 將會暫停,當協程再次恢復時,它將繼續執行觸發鉤子的(Lua)函數的正常執行。
如果此函數從具有待處理 C 調用但沒有繼續函數的線程中調用(稱為 C 調用邊界),或者如果它從沒有在恢復內部運行的線程中調用(通常是主線程),則此函數可能會引發錯誤。
Lua 沒有內置的調試設施。相反,它通過函數和 鉤子 提供了一個特殊的接口。這個接口允許構建不同類型的調試器、分析器和其他需要從解釋器獲取“內部信息”的工具。
lua_Debug
typedef struct lua_Debug { int event; const char *name; /* (n) */ const char *namewhat; /* (n) */ const char *what; /* (S) */ const char *source; /* (S) */ size_t srclen; /* (S) */ int currentline; /* (l) */ int linedefined; /* (S) */ int lastlinedefined; /* (S) */ unsigned char nups; /* (u) number of upvalues */ unsigned char nparams; /* (u) number of parameters */ char isvararg; /* (u) */ char istailcall; /* (t) */ unsigned short ftransfer; /* (r) index of first value transferred */ unsigned short ntransfer; /* (r) number of transferred values */ char short_src[LUA_IDSIZE]; /* (S) */ /* private part */ other fields } lua_Debug;
用於攜帶有關函數或激活記錄的不同信息的結構。 lua_getstack
只填充這個結構的私有部分,以供以後使用。要用有用的信息填充 lua_Debug
的其他字段,必須使用適當的參數調用 lua_getinfo
。(具體來說,要獲取一個字段,必須將字段註釋中的字母添加到 lua_getinfo
的參數 what
中。)
lua_Debug
的欄位具有以下含義
source
: 創建該函數的塊的來源。如果 source
以 '@
' 開頭,表示該函數是在一個帶有文件名跟在 '@
' 後面的文件中定義的。如果 source
以 '=
' 開頭,其餘內容描述了用戶相依的方式。否則,該函數是在一個字符串中定義的,其中 source
就是該字符串。
srclen
: 字符串 source
的長度。
short_src
: source
的可打印版本,用於錯誤消息。
linedefined
: 函數定義開始的行號。
lastlinedefined
: 函數定義結束的行號。
what
: 如果該函數是 Lua 函數,則為字符串 "Lua"
;如果是 C 函數,則為 "C"
;如果是塊的主要部分,則為 "main"
。
currentline
: 給定函數正在執行的當前行。當沒有可用的行信息時,currentline
設置為 -1。
name
: 給定函數的合理名稱。因為 Lua 中的函數是一級值,它們沒有固定的名稱:一些函數可以是多個全局變量的值,而其他一些函數只能存儲在表字段中。 lua_getinfo
函數檢查如何調用函數以找到合適的名稱。如果找不到名稱,則將 name
設置為 NULL
。
namewhat
: 解釋 name
字段。根據調用函數的方式,namewhat
的值可以是 "global"
、"local"
、"method"
、"field"
、"upvalue"
或 ""
(空字符串)。(當沒有其他選擇適用時,Lua 使用空字符串。)
istailcall
: 如果此函數調用是由尾部調用調用的,則為 true。在這種情況下,該級別的調用者不在堆棧中。
nups
: 函數的封閉變量數量。
nparams
: 函數的參數數量(對於 C 函數始終為 0)。
isvararg
: 如果函数是可变参数函数,则为true(对于C函数始终为true)。
ftransfer
: 在堆栈中传递的第一个值的索引,即调用中的参数或返回中的返回值。(其他值位于连续的索引中。)使用此索引,您可以通过 lua_getlocal
和 lua_setlocal
访问和修改这些值。此字段仅在调用钩子期间有意义,表示第一个参数,或在返回钩子期间有意义,表示第一个被返回的值。(对于调用钩子,此值始终为1。)
ntransfer
: 被传递的值的数量(参见前一项)。 (对于调用Lua函数,此值始终等于 nparams
。)
lua_gethook
[-0, +0, –]
lua_Hook lua_gethook (lua_State *L);
返回当前的钩子函数。
lua_gethookcount
[-0, +0, –]
int lua_gethookcount (lua_State *L);
返回当前的钩子计数。
lua_gethookmask
[-0, +0, –]
int lua_gethookmask (lua_State *L);
返回当前的钩子掩码。
lua_getinfo
[-(0|1), +(0|1|2), m]
int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
获取有关特定函数或函数调用的信息。
要获取有关函数调用的信息,参数 ar
必须是由先前调用 lua_getstack
填充的有效激活记录或作为参数传递给钩子(请参见 lua_Hook
)。
要获取有关函数的信息,您需要将其推送到堆栈上,并以字符 '>
' 开头的字符串开始 what
字符串。(在这种情况下,lua_getinfo
从堆栈顶部弹出函数。)例如,要知道函数 f
定义在哪一行,您可以编写以下代码
lua_Debug ar; lua_getglobal(L, "f"); /* get global 'f' */ lua_getinfo(L, ">S", &ar); printf("%d\n", ar.linedefined);
字符串 what
中的每个字符都选择要填充的结构体 ar
的某些字段或要推送到堆栈上的值。(这些字符也在结构体 lua_Debug
的声明中记录,在每个字段后的注释中用括号括起来。)
f
': 推送运行在给定级别的函数到堆栈上;
l
': 填充字段 currentline
;
n
': 填充字段 name
和 namewhat
;
r
': 填充字段 ftransfer
和 ntransfer
;
S
': 填充字段 source
、short_src
、linedefined
、lastlinedefined
和 what
;
t
': 填入字段istailcall
;
u
': 填入字段nups
、nparams
和isvararg
;
L
': 推送一個表格到堆疊上,其索引是函數的行,具有一些相關聯的代碼,即可以設置斷點的行。(沒有代碼的行包括空行和註釋。)如果與選項'f
'一起給出,則在函數之後推送其表格。這是唯一可能引發內存錯誤的選項。
該函數返回0來表示what
中的無效選項;即使如此,有效選項也會被正確處理。
lua_getlocal
[-0, +(0|1), –]
const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
獲取有關給定激活記錄或給定函數的本地變量或臨時值的信息。
在第一種情況下,參數ar
必須是由先前對lua_getstack
的調用填充或作為鉤子的參數(參見lua_Hook
)給定的有效激活記錄。索引n
選擇要檢查的本地變量;有關變量索引和名稱的詳細信息,請參見debug.getlocal
。
lua_getlocal
將變量的值推送到堆疊上並返回其名稱。
在第二種情況下,ar
必須為NULL
,要檢查的函數必須在堆疊頂部。在這種情況下,僅能看到Lua函數的參數(因為沒有關於哪些變量是活動的信息),並且不會將任何值推送到堆疊上。
當索引大於活動本地變量的數量時,返回NULL
(並且不推送任何內容)。
lua_getstack
[-0, +0, –]
int lua_getstack (lua_State *L, int level, lua_Debug *ar);
獲取有關解譯器運行時堆疊的信息。
該函數將lua_Debug結構的部分填充為正在給定級別執行的函數的激活記錄的標識。級別0是當前運行的函數,而級別n+1是調用級別n的函數(尾調用除外,尾調用不計入堆疊)。當使用大於堆疊深度的級別調用時,lua_getstack
返回0;否則返回1。
lua_getupvalue
[-0, +(0|1), –]
const char *lua_getupvalue (lua_State *L, int funcindex, int n);
獲取索引為funcindex
的閉包的第n
個上值的資訊。將該上值的值壓入堆疊並返回其名稱。當索引n
大於上值的數量時,返回NULL
(並且不壓入任何內容)。
有關上值的更多資訊,請參閱debug.getupvalue
。
lua_Hook
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
用於調試鉤子函數的類型。
每當調試鉤子被調用時,其ar
參數的event
字段都會設置為觸發該鉤子的特定事件。Lua使用以下常數標識這些事件:LUA_HOOKCALL
、LUA_HOOKRET
、LUA_HOOKTAILCALL
、LUA_HOOKLINE
和LUA_HOOKCOUNT
。此外,對於行事件,還會設置currentline
字段。要獲取ar
中的任何其他字段的值,鉤子必須調用lua_getinfo
。
對於調用事件,event
可以是LUA_HOOKCALL
(正常值)或LUA_HOOKTAILCALL
(用於尾部調用);在這種情況下,將不會有相應的返回事件。
當Lua運行鉤子時,它會禁用對其他鉤子的調用。因此,如果鉤子調用Lua來執行函數或塊,則此執行將在沒有對鉤子的任何調用的情況下發生。
鉤子函數不能具有繼續,也就是說,它們不能使用非空的k
調用lua_yieldk
、lua_pcallk
或lua_callk
。
鉤子函數可以在以下條件下產生:只有計數和行事件可以產生;要產生,鉤子函數必須完成其執行並調用nresults
等於零的lua_yield
(即,不返回任何值)。
lua_sethook
[-0, +0, –]
void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);
設置調試鉤子函數。
參數f
是鉤子函數。mask
指定鉤子將在哪些事件上被調用:它由LUA_MASKCALL
、LUA_MASKRET
、LUA_MASKLINE
和LUA_MASKCOUNT
的位或組成。當掩碼包含LUA_MASKCOUNT
時,count
參數才有意義。對於每個事件,鉤子的調用如下所述
count
指令後調用。此事件僅在 Lua 執行 Lua 函數時發生。
通過將 mask
設置為零來禁用勾子。
lua_setlocal
[-(0|1), +0, –]
const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
設置給定啟動記錄的本地變量的值。它將堆疊頂部的值賦給變量並返回其名稱。它還從堆疊中彈出值。
當索引大於活動本地變量數量時,返回 NULL
(並且不彈出任何內容)。
參數 ar
和 n
如同函數 lua_getlocal
。
lua_setupvalue
[-(0|1), +0, –]
const char *lua_setupvalue (lua_State *L, int funcindex, int n);
設置閉包的上值的值。它將堆疊頂部的值賦給上值並返回其名稱。它還從堆疊中彈出值。
當索引 n
大於上值數量時,返回 NULL
(並且不彈出任何內容)。
參數 funcindex
和 n
如同函數 lua_getupvalue
。
lua_upvalueid
[-0, +0, –]
void *lua_upvalueid (lua_State *L, int funcindex, int n);
返回索引 funcindex
的閉包中第 n
個上值的唯一標識符。
這些唯一標識符允許程序檢查不同的閉包是否共享上值。對於訪問相同外部本地變量的 Lua 閉包,它們將對這些上值索引返回相同的 id。
參數 funcindex
和 n
如同函數 lua_getupvalue
,但 n
不能大於上值數量。
lua_upvaluejoin
[-0, +0, –]
void lua_upvaluejoin (lua_State *L, int funcindex1, int n1, int funcindex2, int n2);
使索引為 funcindex1
的 Lua 閉包的第 n1
個上值參考索引為 funcindex2
的 Lua 閉包的第 n2
個上值。
輔助函式庫提供了幾個方便的功能,用於將C與Lua進行接口。基本API提供了C與Lua之間所有交互的原始函數,而輔助函式庫提供了一些常見任務的更高級別的功能。
所有輔助函式庫中的函數和類型都定義在標頭文件lauxlib.h
中,並帶有前綴luaL_
。
輔助函式庫中的所有函數都建立在基本API之上,因此它們提供的功能都可以使用該API實現。然而,使用輔助函式庫可以確保代碼的一致性。
輔助函式庫中的幾個函數在內部使用了一些額外的堆棧槽。當輔助函式庫中的函數使用的堆棧槽少於五個時,它不會檢查堆棧大小;它只是假定有足夠的槽。
輔助函式庫中的幾個函數用於檢查C函數的參數。由於錯誤消息是針對參數格式化的(例如,"bad argument #1
"),因此不應將這些函數用於其他堆棧值。
名稱為luaL_check*
的函數如果檢查不滿足,將始終引發錯誤。
這裡按字母順序列出了輔助函式庫中的所有函數和類型。
luaL_addchar
[-?, +?, m]
void luaL_addchar (luaL_Buffer *B, char c);
將字節c
添加到緩衝區B
(參見luaL_Buffer
)。
luaL_addgsub
[-?, +?, m]
const void luaL_addgsub (luaL_Buffer *B, const char *s, const char *p, const char *r);
將字符串s
的副本添加到緩衝區B
(參見luaL_Buffer
),將字符串p
的任何出現替換為字符串r
。
luaL_addlstring
[-?, +?, m]
void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
將由指針s
指向的長度l
的字符串添加到緩衝區B
(參見luaL_Buffer
)。字符串可以包含嵌入的零。
luaL_addsize
[-?, +?, –]
void luaL_addsize (luaL_Buffer *B, size_t n);
向緩衝區B
添加先前複製到緩衝區區域的長度為n
的字符串(參見luaL_prepbuffer
)。
luaL_addstring
[-?, +?, m]
void luaL_addstring (luaL_Buffer *B, const char *s);
將由指針s
指向的以零結尾的字符串添加到緩衝區B
(參見luaL_Buffer
)。
luaL_addvalue
[-?, +?, m]
void luaL_addvalue (luaL_Buffer *B);
將堆棧頂部的值添加到緩衝區B
(參見luaL_Buffer
)。彈出值。
這是關於字符串緩衝區的唯一一個函數,可以(並且必須)使用堆棧上的額外元素調用,這個元素是要添加到緩衝區的值。
luaL_argcheck
[-0, +0, v]
void luaL_argcheck (lua_State *L, int cond, int arg, const char *extramsg);
檢查cond
是否為真。如果不是,則使用標準消息引發錯誤(參見luaL_argerror
)。
luaL_argerror
[-0, +0, v]
int luaL_argerror (lua_State *L, int arg, const char *extramsg);
使用標準消息引發有關調用它的C函數的參數arg
的問題的錯誤,該消息包含extramsg
作為注釋
bad argument #arg to 'funcname' (extramsg)
此函數永遠不返回。
luaL_argexpected
[-0, +0, v]
void luaL_argexpected (lua_State *L, int cond, int arg, const char *tname);
檢查cond
是否為真。如果不是,則引發有關參數arg
的類型的錯誤,其中包含標準消息(參見luaL_typeerror
)。
luaL_Buffer
typedef struct luaL_Buffer luaL_Buffer;
請為 字串緩衝區 輸入。
字串緩衝區允許 C 程式碼逐步建立 Lua 字串。其使用模式如下所示
b
變數,類型為 luaL_Buffer
。luaL_buffinit(L, &b)
進行初始化。luaL_add*
函式將字串片段添加到緩衝區中。
luaL_pushresult(&b)
。此呼叫將最終字串留在堆疊的頂端。
如果您事先知道所產生字串的最大大小,則可以像這樣使用緩衝區
b
變數,類型為 luaL_Buffer
。luaL_buffinitsize(L, &b, sz)
進行初始化並預先分配大小為 sz
的空間。luaL_pushresultsize(&b, sz)
,其中 sz
是複製到該空間的結果字串的總大小(可能小於或等於預先分配的大小)。
在正常操作期間,字串緩衝區使用變數數量的堆疊槽位。因此,在使用緩衝區時,您不能假設您知道堆疊的頂端在哪裡。您可以在連續的緩衝區操作之間使用堆疊,只要該使用是平衡的;也就是說,當您呼叫緩衝區操作時,堆疊的水平與前一個緩衝區操作之後的水平相同。(此規則的唯一例外是 luaL_addvalue
。)在呼叫 luaL_pushresult
後,堆疊恢復到初始化緩衝區時的水平,加上其頂端的最終字串。
luaL_buffaddr
[-0, +0, –]
char *luaL_buffaddr (luaL_Buffer *B);
返回緩衝區 B
(參見 luaL_Buffer
)的當前內容的地址。請注意,對緩衝區的任何添加都可能使此地址無效。
luaL_buffinit
[-0, +?, –]
void luaL_buffinit (lua_State *L, luaL_Buffer *B);
初始化緩衝區 B
(參見 luaL_Buffer
)。此函式不分配任何空間;必須將緩衝區宣告為變數。
luaL_bufflen
[-0, +0, –]
size_t luaL_bufflen (luaL_Buffer *B);
返回緩衝區 B
(參見 luaL_Buffer
)的當前內容的長度。
luaL_buffinitsize
[-?, +?, m]
char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz);
等同於序列 luaL_buffinit
,luaL_prepbuffsize
。
luaL_buffsub
[-?, +?, –]
void luaL_buffsub (luaL_Buffer *B, int n);
從緩衝區 B
(參見 luaL_Buffer
)中刪除 n
個位元組。緩衝區必須至少具有該數量的位元組。
luaL_callmeta
[-0, +(0|1), e]
int luaL_callmeta (lua_State *L, int obj, const char *e);
呼叫元方法。
如果索引 obj
的物件具有元表,且此元表具有欄位 e
,則此函式將呼叫該欄位並將物件作為其唯一參數。在這種情況下,此函式將返回 true,並將呼叫的值壓入堆疊。如果沒有元表或沒有元方法,則此函式將返回 false,而不在堆疊上壓入任何值。
luaL_checkany
[-0, +0, v]
void luaL_checkany (lua_State *L, int arg);
檢查函式在位置 arg
是否具有任何類型(包括 nil)的參數。
luaL_checkinteger
[-0, +0, v]
lua_Integer luaL_checkinteger (lua_State *L, int arg);
檢查函數引數 arg
是否為整數(或可轉換為整數),並返回該整數。
luaL_checklstring
[-0, +0, v]
const char *luaL_checklstring (lua_State *L, int arg, size_t *l);
檢查函數引數 arg
是否為字符串,並返回該字符串;如果 l
不為 NULL
,則將其引用填充為字符串的長度。
此函數使用 lua_tolstring
來獲取其結果,因此所有轉換和注意事項都適用於此處。
luaL_checknumber
[-0, +0, v]
lua_Number luaL_checknumber (lua_State *L, int arg);
檢查函數引數 arg
是否為數字,並返回將該數字轉換為 lua_Number
的結果。
luaL_checkoption
[-0, +0, v]
int luaL_checkoption (lua_State *L, int arg, const char *def, const char *const lst[]);
檢查函數引數 arg
是否為字符串,並在陣列 lst
(必須以 NULL 結尾)中搜索該字符串。返回找到字符串的陣列中的索引。如果引數不是字符串或找不到字符串,則引發錯誤。
如果 def
不為 NULL
,則當沒有引數 arg
或此引數為 nil 時,函數將使用 def
作為默認值。
這是一個將字符串映射到 C 枚舉的有用函數。(Lua 函數庫中的常規慣例是使用字符串而不是數字來選擇選項。)
luaL_checkstack
[-0, +0, v]
void luaL_checkstack (lua_State *L, int sz, const char *msg);
將堆棧大小擴展到 top + sz
元素,如果堆棧無法擴展到該大小則引發錯誤。 msg
是要添加到錯誤消息中的額外文本(或對於沒有額外文本的情況,為 NULL
)。
luaL_checkstring
[-0, +0, v]
const char *luaL_checkstring (lua_State *L, int arg);
檢查函數引數 arg
是否為字符串,並返回該字符串。
此函數使用 lua_tolstring
來獲取其結果,因此所有轉換和注意事項都適用於此處。
luaL_checktype
[-0, +0, v]
void luaL_checktype (lua_State *L, int arg, int t);
檢查函數引數 arg
是否具有類型 t
。有關 t
的類型編碼,請參見 lua_type
。
luaL_checkudata
[-0, +0, v]
void *luaL_checkudata (lua_State *L, int arg, const char *tname);
檢查函數引數 arg
是否為類型 tname
的用戶數據(參見 luaL_newmetatable
),並返回用戶數據的內存塊地址(參見 lua_touserdata
)。
luaL_checkversion
[-0, +0, v]
void luaL_checkversion (lua_State *L);
檢查調用代碼和被調用的 Lua 函數庫是否使用相同版本的 Lua 和相同的數字類型。
luaL_dofile
[-0, +?, m]
int luaL_dofile (lua_State *L, const char *filename);
加載並運行給定的文件。它被定義為以下宏
(luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
如果沒有錯誤,它返回 0(LUA_OK
),否則在發生錯誤時返回 1。
luaL_dostring
[-0, +?, –]
int luaL_dostring (lua_State *L, const char *str);
加載並運行給定的字符串。它被定義為以下宏
(luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))
如果沒有錯誤,它返回 0(LUA_OK
),否則在發生錯誤時返回 1。
luaL_error
[-0, +0, v]
int luaL_error (lua_State *L, const char *fmt, ...);
引發錯誤。錯誤消息的格式由 fmt
加上任何額外的參數組成,遵循 lua_pushfstring
的相同規則。如果有可用的文件名和發生錯誤的行號信息,它還會在消息的開頭添加這些信息。
這個函數永遠不會返回,但在 C 函數中使用它作為 return luaL_error(args)
的慣用方法。
luaL_execresult
[-0, +3, m]
int luaL_execresult (lua_State *L, int stat);
此函數生成標準庫中與進程相關的函數(os.execute
和 io.close
)的返回值。
luaL_fileresult
[-0, +(1|3), m]
int luaL_fileresult (lua_State *L, int stat, const char *fname);
此函數生成標準庫中與文件相關的函數(io.open
、os.rename
、file:seek
等)的返回值。
luaL_getmetafield
[-0, +(0|1), m]
int luaL_getmetafield (lua_State *L, int obj, const char *e);
從索引 obj
的對象的元表中推送字段 e
,並返回推送值的類型。如果對象沒有元表,或者元表沒有此字段,則不推送任何內容並返回 LUA_TNIL
。
luaL_getmetatable
[-0, +1, m]
int luaL_getmetatable (lua_State *L, const char *tname);
將名稱 tname
在註冊表中關聯的元表壓入堆棧(參見 luaL_newmetatable
),如果沒有與該名稱關聯的元表則壓入 nil。返回推送值的類型。
luaL_getsubtable
[-0, +1, e]
int luaL_getsubtable (lua_State *L, int idx, const char *fname);
確保索引 idx
的值 t[fname]
(其中 t
是索引 idx
的值)為表,並將該表壓入堆棧。如果在該處找到先前的表,返回 true;如果創建了新表,返回 false。
luaL_gsub
[-0, +1, m]
const char *luaL_gsub (lua_State *L, const char *s, const char *p, const char *r);
創建字符串 s
的副本,將字符串 p
的任何出現替換為字符串 r
。將結果字符串推送到堆棧並返回它。
luaL_len
[-0,+0,e]
lua_Integer luaL_len (lua_State *L, int index);
返回給定索引的值的“長度”作為數字;它等效於 Lua 中的 '#
' 運算符(參見 §3.4.7)。如果操作的結果不是整數,則引發錯誤。(這種情況只能通過元方法發生。)
luaL_loadbuffer
[-0, +1, –]
int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, const char *name);
相當於 luaL_loadbufferx
,其 mode
參數設為 NULL
。
luaL_loadbufferx
[-0, +1, –]
int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode);
將緩衝區載入為 Lua 塊。此函數使用 lua_load
載入由 buff
指向且大小為 sz
的緩衝區中的塊。
此函數返回與 lua_load
相同的結果。 name
為塊名,用於調試信息和錯誤消息。字符串 mode
的作用與函數 lua_load
中的相同。
luaL_loadfile
[-0, +1, m]
int luaL_loadfile (lua_State *L, const char *filename);
相當於 luaL_loadfilex
,其 mode
參數設為 NULL
。
luaL_loadfilex
[-0, +1, m]
int luaL_loadfilex (lua_State *L, const char *filename, const char *mode);
將文件載入為 Lua 塊。此函數使用 lua_load
載入名為 filename
的文件中的塊。如果 filename
為 NULL
,則從標準輸入載入。如果文件中的第一行以 #
開頭,則忽略該行。
字符串 mode
的作用與函數 lua_load
中的相同。
此函數返回與 lua_load
或 LUA_ERRFILE
(用於與文件相關的錯誤)相同的結果。
與 lua_load
一樣,此函數僅載入塊,不運行它。
luaL_loadstring
[-0, +1, –]
int luaL_loadstring (lua_State *L, const char *s);
將字符串載入為 Lua 塊。此函數使用 lua_load
載入以零終止的字符串 s
中的塊。
此函數返回與 lua_load
相同的結果。
與 lua_load
一樣,此函數僅載入塊,不運行它。
luaL_newlib
[-0, +1, m]
void luaL_newlib (lua_State *L, const luaL_Reg l[]);
創建一個新表並在其中註冊列表 l
中的函數。
其實現為以下宏
(luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
數組 l
必須是實際數組,而不是指向它的指針。
luaL_newlibtable
[-0, +1, m]
void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);
創建一個新表,其大小優化為存儲數組 l
中的所有項目(但實際上不存儲它們)。它旨在與 luaL_setfuncs
(參見 luaL_newlib
)一起使用。
其實現為一個宏。數組 l
必須是實際數組,而不是指向它的指針。
luaL_newmetatable
[-0, +1, m]
int luaL_newmetatable (lua_State *L, const char *tname);
如果註冊表已經有鍵 tname
,返回0。否則,創建一個新表用作userdata的metatable,將對 __name = tname
的配對添加到這個新表中,將對 [tname] = new table
的配對添加到註冊表中,並返回1。
無論哪種情況,該函數都會將與註冊表中 tname
相關聯的最終值壓入堆棧。
luaL_newstate
[-0, +0, –]
lua_State *luaL_newstate (void);
創建一個新的Lua狀態。它使用基於ISO C分配函數的分配器調用 lua_newstate
,然後設置警告函數和恐慌函數(參見 §4.4),以將消息打印到標準錯誤輸出。
返回新狀態,如果存在記憶體分配錯誤,則返回NULL
。
luaL_openlibs
[-0,+0,e]
void luaL_openlibs (lua_State *L);
將所有標準Lua庫打開到給定的狀態中。
luaL_opt
[-0, +0, –]
T luaL_opt (L, func, arg, dflt);
此宏定義如下
(lua_isnoneornil(L,(arg)) ? (dflt) : func(L,(arg)))
簡單來說,如果參數 arg
是nil或不存在,則該宏將產生默認的 dflt
。否則,它將以狀態 L
和參數索引 arg
調用 func
的結果作為結果。請注意,它僅在需要時評估表達式 dflt
。
luaL_optinteger
[-0, +0, v]
lua_Integer luaL_optinteger (lua_State *L, int arg, lua_Integer d);
如果函數參數 arg
是整數(或可轉換為整數),則返回該整數。如果此參數不存在或為nil,則返回d
。否則,引發錯誤。
luaL_optlstring
[-0, +0, v]
const char *luaL_optlstring (lua_State *L, int arg, const char *d, size_t *l);
如果函數參數 arg
是字符串,則返回該字符串。如果此參數不存在或為nil,則返回d
。否則,引發錯誤。
如果l
不是NULL
,則將其參考填充為結果的長度。如果結果為NULL
(僅在返回d
和d == NULL
時可能),則其長度被視為零。
此函數使用 lua_tolstring
來獲取其結果,因此所有轉換和注意事項都適用於此處。
luaL_optnumber
[-0, +0, v]
lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number d);
如果函數參數 arg
是數字,則將此數字作為lua_Number
返回。如果此參數不存在或為nil,則返回d
。否則,引發錯誤。
luaL_optstring
[-0, +0, v]
const char *luaL_optstring (lua_State *L, int arg, const char *d);
如果函數參數 arg
是字符串,則返回該字符串。如果此參數不存在或為nil,則返回d
。否則,引發錯誤。
luaL_prepbuffer
[-?, +?, m]
char *luaL_prepbuffer (luaL_Buffer *B);
相當於具有預定義大小luaL_prepbuffsize
的LUAL_BUFFERSIZE
。
luaL_prepbuffsize
[-?, +?, m]
char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz);
返回大小為sz
的空間地址,您可以將要添加到緩衝區B
(參見luaL_Buffer
)的字符串複製到該空間中。將字符串複製到此空間後,必須調用luaL_addsize
,並傳入字符串的大小,以實際將其添加到緩衝區。
luaL_pushfail
[-0, +1, –]
void luaL_pushfail (lua_State *L);
將fail值壓入堆棧(參見§6)。
luaL_pushresult
[-?, +1, m]
void luaL_pushresult (luaL_Buffer *B);
結束使用緩衝區B
,將最終字串留在堆疊頂部。
luaL_pushresultsize
[-?, +1, m]
void luaL_pushresultsize (luaL_Buffer *B, size_t sz);
等同於序列luaL_addsize
,luaL_pushresult
。
luaL_ref
[-1, +0, m]
int luaL_ref (lua_State *L, int t);
在索引t
的表中為堆疊頂部的對象創建並返回一個參考(reference),並彈出該對象。
參考是一個唯一的整數鍵。只要您不手動將整數鍵添加到表t
中,luaL_ref
就會確保返回的鍵是唯一的。您可以通過調用lua_rawgeti(L, t, r)
來檢索由參考r
引用的對象。函數luaL_unref
釋放一個參考。
如果堆疊頂部的對象是nil,luaL_ref
將返回常數LUA_REFNIL
。常數LUA_NOREF
保證與luaL_ref
返回的任何參考都不同。
luaL_Reg
typedef struct luaL_Reg { const char *name; lua_CFunction func; } luaL_Reg;
要由luaL_setfuncs
註冊的函數陣列的類型。 name
是函數名,func
是指向函數的指針。任何luaL_Reg
陣列都必須以一個發信號的條目結束,其中name
和func
都是NULL
。
luaL_requiref
[-0, +1, e]
void luaL_requiref (lua_State *L, const char *modname, lua_CFunction openf, int glb);
如果package.loaded[modname]
不為真,則使用字符串modname
作為參數調用函數openf
,並將調用結果設置為package.loaded[modname]
,就好像通過require
調用該函數一樣。
如果glb
為真,還將模塊存儲到全局modname
中。
在堆疊上留下模塊的副本。
luaL_setfuncs
[-nup,+0,m]
void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
將陣列l
中的所有函數(參見luaL_Reg
)註冊到堆疊頂部的表中(下面是可選的上值,請參見下一步)。
當nup
不為零時,所有函數都將使用nup
上值創建,這些上值初始化為先前在函數庫表的堆疊頂部推送的nup
值的副本。註冊後,這些值將從堆棧中彈出。
具有NULL
值的函數表示佔位符,佔位符將填充為false。
luaL_setmetatable
[-0, +0, –]
void luaL_setmetatable (lua_State *L, const char *tname);
將堆疊頂部對象的元表設置為註冊表中與名稱tname
關聯的元表(請參見luaL_newmetatable
)。
luaL_Stream
typedef struct luaL_Stream { FILE *f; lua_CFunction closef; } luaL_Stream;
標準I/O庫使用的文件處理程序的標準表示形式。
檔案處理程式碼以完整的 userdata 實作,擁有一個名為 LUA_FILEHANDLE
的 metatable(其中 LUA_FILEHANDLE
是實際 metatable 名稱的巨集)。這個 metatable 是由 I/O 函式庫創建的(參見 luaL_newmetatable
)。
這個 userdata 必須以結構 luaL_Stream
開頭;在這個初始結構之後可以包含其他資料。欄位 f
指向相應的 C 流(或者可以是 NULL
,表示尚未完全建立的處理程式碼)。欄位 closef
指向一個 Lua 函式,當處理程式碼關閉或收集時將呼叫此函式;此函式以處理程式碼作為唯一參數,並且必須返回 true 值(表示成功)或者 false 值加上一個錯誤訊息(表示錯誤)。一旦 Lua 呼叫此欄位,就會將欄位值更改為 NULL
,以表示處理程式碼已關閉。
luaL_testudata
[-0, +0, m]
void *luaL_testudata (lua_State *L, int arg, const char *tname);
此函式與 luaL_checkudata
類似,但當測試失敗時,它返回 NULL
而不是引發錯誤。
luaL_tolstring
[-0, +1, e]
const char *luaL_tolstring (lua_State *L, int idx, size_t *len);
將給定索引處的任意 Lua 值轉換為 C 字串,以合理的格式。結果字串被壓入堆疊並同時被函式返回(參見 §4.1.3)。如果 len
不是 NULL
,函式還會將字串長度設置為 *len
。
如果值具有帶有 __tostring
欄位的 metatable,則 luaL_tolstring
會使用值作為參數調用相應的元方法,並使用調用的結果作為其結果。
luaL_traceback
[-0, +1, m]
void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level);
創建並推送堆疊 L1
的回溯。如果 msg
不是 NULL
,則它將附加在回溯的開頭。 level
參數告訴在哪個層級開始回溯。
luaL_typeerror
[-0, +0, v]
int luaL_typeerror (lua_State *L, int arg, const char *tname);
針對呼叫它的 C 函式的參數 arg
引發一個標準消息的類型錯誤;tname
是預期類型的“名稱”。此函式永遠不會返回。
luaL_typename
[-0, +0, –]
const char *luaL_typename (lua_State *L, int index);
返回給定索引處的值的類型名稱。
luaL_unref
[-0, +0, –]
void luaL_unref (lua_State *L, int t, int ref);
從索引 t
的表中釋放參考 ref
(參見 luaL_ref
)。條目將從表中刪除,以便可以收集引用的對象。參考 ref
也將被釋放以便再次使用。
若 ref
為 LUA_NOREF
或 LUA_REFNIL
,則 luaL_unref
不執行任何操作。
luaL_where
[-0, +1, m]
void luaL_where (lua_State *L, int lvl);
將目前控制流在呼叫堆疊中第 lvl
層的位置識別字串推送至堆疊上。通常,此字串具有以下格式:
chunkname:currentline:
第 0 層為運行中的函數,第 1 層為呼叫運行中的函數的函數,依此類推。
此函數用於建立錯誤訊息的前綴。
標準 Lua 库提供了一些在 C 語言中通過 C API 實現的實用功能。其中一些功能為語言提供了基本服務(例如,type
和 getmetatable
);其他功能提供了對外部服務的訪問(例如,I/O);還有一些可能可以在 Lua 中實現,但出於不同的原因值得在 C 中實現(例如,table.sort
)。
所有庫均通過官方的 C API 實現,並以單獨的 C 模塊提供。除非另有說明,這些庫函數不會將其參數的數量調整為其期望的參數。例如,文檔中記錄為 foo(arg)
的函數不應該在沒有參數的情況下被調用。
標註 fail 表示某種失敗的假值。(目前,fail 等於 nil,但這可能會在未來版本中更改。建議始終使用 (not status)
來測試這些函數的成功與否,而不是使用 (status == nil)
。)
目前,Lua 具有以下標準庫
除了基本和套件庫外,每個庫都將其所有函數作為全局表的字段或其對象的方法提供。
要訪問這些庫,C 主程序應該調用 luaL_openlibs
函數,該函數將打開所有標準庫。或者,主程序可以通過使用 luaL_requiref
來分別調用 luaopen_base
(基本庫)、luaopen_package
(套件庫)、luaopen_coroutine
(協程庫)、luaopen_string
(字串庫)、luaopen_utf8
(UTF-8 库)、luaopen_table
(表庫)、luaopen_math
(數學庫)、luaopen_io
(I/O 库)、luaopen_os
(操作系統庫)和 luaopen_debug
(調試庫)。這些函數在 lualib.h
基本庫提供 Lua 的核心功能。如果您的應用程序中不包含此庫,您應該仔細檢查是否需要為其中一些功能提供實現。
assert (v [, message])
如果其參數 v
的值為 false(即 nil 或 false),則引發錯誤;否則,返回其所有參數。在錯誤情況下,message
為錯誤對象;當缺少時,默認為 "assertion failed!
"
collectgarbage ([opt [, arg]])
此函數是垃圾收集器的通用接口。根據其第一個參數 opt
的不同,它執行不同的功能
collect
": 執行完整的垃圾收集循環。這是默認選項。
stop
": 停止垃圾收集器的自動執行。收集器只在顯式調用之前運行,直到重新啟動它。
restart
": 重新啟動垃圾收集器的自動執行。
count
": 返回 Lua 使用的總內存(以Kbytes為單位)。該值具有小數部分,因此乘以 1024 可以得到 Lua 使用的確切字節數。
step
": 執行垃圾收集步驟。步驟的 "大小" 受 arg
控制。對於零值,收集器將執行一個基本(不可分割)步驟。對於非零值,收集器將執行好像 Lua 分配了該量的內存(以Kbytes為單位)。如果步驟完成了一個收集循環,則返回 true。
isrunning
": 返回一個布林值,指示收集器是否正在運行(即未停止)。
incremental
": 將收集器模式更改為增量模式。此選項後面可以跟三個數字:垃圾收集器暫停、步驟乘數和步驟大小(請參見 §2.5.1)。零表示不更改該值。
generational
": 將收集器模式更改為代際模式。此選項後面可以跟兩個數字:垃圾收集器次要乘數和主要乘數(請參見 §2.5.2)。零表示不更改該值。
有關垃圾收集和其中一些選項的更多詳細信息,請參見 §2.5。
不應由終結器調用此函數。
dofile ([filename])
dofile
執行標準輸入(stdin
)的內容。返回塊返回的所有值。在錯誤情況下,dofile
將錯誤傳播給其調用者。(即,dofile
不運行在保護模式下。)
error (message [, level])
message
作為錯誤對象引發錯誤(參見§2.3)。此函數永遠不會返回。
通常,error
在消息開頭添加有關錯誤位置的一些信息(如果消息是字符串)。level
參數指定如何獲取錯誤位置。使用level 1(默認值),錯誤位置是error
函數被調用的位置。Level 2將錯誤指向調用error
的函數所在的位置;以此類推。傳遞level 0可以避免將錯誤位置信息添加到消息中。
_G
getmetatable (object)
如果object
沒有元表,則返回nil。否則,如果對象的元表具有__metatable
字段,則返回相關值。否則,返回給定對象的元表。
ipairs (t)
返回三個值(一個迭代器函數,表t
和0),以便構造
for i,v in ipairs(t) do body end
將遍歷鍵-值對(1,t[1]
),(2,t[2]
),...,直到第一個不存在的索引。
load (chunk [, chunkname [, mode [, env]]])
加載一個塊。
如果chunk
是字符串,則塊是這個字符串。如果chunk
是一個函數,load
重複調用它以獲取塊片段。每次對chunk
的調用都必須返回一個與前一個結果連接的字符串。返回空字符串、nil或沒有值表示塊的結尾。
如果沒有語法錯誤,load
將編譯塊作為一個函數返回;否則,它返回fail加上錯誤消息。
當加載主塊時,結果函數將始終具有一個封閉值,即_ENV
變量(參見§2.2)。然而,當加載從函數創建的二進制塊(參見string.dump
)時,結果函數可以具有任意數量的封閉值,並且不能保證其第一個封閉值將是_ENV
變量。(非主函數甚至可能沒有_ENV
封閉值。)
無論如何,如果結果函數具有任何封閉值,其第一個封閉值將設置為env
的值(如果給定了該參數),否則設置為全局環境的值。其他封閉值初始化為nil。所有封閉值都是新的,即它們不與任何其他函數共享。
chunkname
用於錯誤訊息和調試信息的塊的名稱(見§4.7)。當不存在時,如果 chunk
是字符串,則默認為 chunk
,否則默認為 "=(load)
"。
字符串 mode
控制塊是否可以是文本或二進制(即預編譯的塊)。它可以是字符串 "b
"(僅二進制塊)、"t
"(僅文本塊)或 "bt
"(二進制和文本)。默認為 "bt
"。
加載格式錯誤的二進制塊是安全的;load
會發出適當的錯誤信號。但是,Lua 不檢查二進制塊內部代碼的一致性;運行惡意製作的字節碼可能會使解釋器崩潰。
loadfile ([filename [, mode [, env]]])
類似於 load
,但是從文件 filename
或從標準輸入獲取塊,如果未給出文件名。
next (table [, index])
允許程序遍歷表的所有字段。它的第一個參數是一個表,第二個參數是該表中的索引。調用 next
返回表的下一個索引及其相關聯的值。當作為第二個參數調用為 nil 時,next
返回初始索引及其相關聯的值。當以最後一個索引或在空表中以 nil 調用時,next
返回 nil。如果第二個參數缺失,則將其解釋為 nil。特別地,可以使用 next(t)
來檢查表是否為空。
枚舉索引的順序未指定,即使是數字索引也是如此。 (要按數字順序遍歷表,請使用數值 for。)
在遍歷表時,不應將任何值賦給不存在的字段。但是,可以修改現有的字段。特別地,可以將現有字段設置為 nil。
pairs (t)
如果 t
具有元方法 __pairs
,則使用 t
作為參數調用它並返回調用的前三個結果。
否則,返回三個值:函數 next
、表 t
和 nil,以便構造
for k,v in pairs(t) do body end
將遍歷表 t
的所有鍵值對。
參見函數 next
以了解在遍歷表時修改表的注意事項。
pcall (f [, arg1, ···])
以 保護模式 調用函數 f
並傳遞給定的參數。這意味著 f
內的任何錯誤都不會傳播;相反,pcall
捕捉錯誤並返回狀態碼。它的第一個結果是狀態碼(布林值),如果調用成功且沒有錯誤,則為 true。在這種情況下,pcall
也會返回調用後的所有結果,此後是第一個結果。如果有任何錯誤,pcall
將返回 false 加上錯誤對象。請注意,被 pcall
捕獲的錯誤不會調用消息處理程序。
print (···)
stdout
,將每個參數轉換為字符串,遵循與 tostring
相同的規則。
函數 print
不是為格式化輸出而設計的,而僅僅是顯示值的一種快速方式,例如用於調試。要完全控制輸出,請使用 string.format
和 io.write
。
rawequal (v1, v2)
v1
是否等於 v2
,而不調用 __eq
元方法。返回一個布林值。
rawget (table, index)
table[index]
的實際值,而不使用 __index
元值。 table
必須是一個表; index
可以是任何值。
rawlen (v)
v
的長度,它必須是一個表或一個字符串,而不調用 __len
元方法。返回一個整數。
rawset (table, index, value)
table[index]
的實際值設置為 value
,而不使用 __newindex
元值。 table
必須是一個表,index
不能是 nil 或 NaN,value
可以是任何 Lua 值。
此函數返回 table
。
select (index, ···)
如果 index
是一個數字,則返回從參數號碼 index
後的所有參數;負數索引從末尾開始(-1 是最後一個參數)。否則,index
必須是字符串 "#"
,並且 select
返回它接收到的額外參數的總數。
setmetatable (table, metatable)
為給定的表設置元表。如果 metatable
為 nil,則刪除給定表的元表。如果原始元表具有 __metatable
字段,則引發錯誤。
此函數返回 table
。
要從 Lua 代碼更改其他類型的元表,必須使用調試庫(§6.10)。
tonumber (e [, base])
如果不帶 base
調用,tonumber
試圖將其參數轉換為數字。如果參數已經是一個數字或可轉換為數字的字符串,則 tonumber
返回該數字;否則,返回 fail。
字符串的轉換可以產生整數或浮點數,根據 Lua 的語法慣例(見 §3.1)。字符串可能有前導和尾隨空格以及符號。
當使用 base
呼叫時,e
必須是一個字符串,以該基數解釋為整數數字。基數可以是介於 2 到 36 之間的任何整數,包括邊界值。在大於 10 的基數中,字母 'A
'(無論大小寫)表示為 10,'B
' 表示為 11,以此類推,'Z
' 表示為 35。如果字符串 e
在給定基數中不是有效的數字,則函數返回 fail。
tostring (v)
接收任何類型的值並將其轉換為人類可讀格式的字符串。
如果 v
的元表具有 __tostring
字段,則 tostring
使用具有 v
作為參數的對應值進行調用,並將調用的結果用作其結果。否則,如果 v
的元表具有字符串值的 __name
字段,tostring
可能會在其最終結果中使用該字符串。
要完全控制數字如何轉換,請使用 string.format
。
type (v)
返回其唯一參數的類型,編碼為字符串。此函數的可能結果是 "nil
"(一個字符串,而不是值 nil),"number
","string
","boolean
","table
","function
","thread
" 和 "userdata
"。
_VERSION
一個全局變量(不是函數),保存包含正在運行的 Lua 版本的字符串。此變量的當前值是 "Lua 5.4
"。
warn (msg1, ···)
發出一個警告,其消息由所有參數的串聯組成(應為字符串)。
按照慣例,以 '@
' 開頭的一段消息意味著是一個控制消息,這是發送給警告系統本身的消息。特別是,在 Lua 中的標準警告函數識別控制消息 "@off
",以停止發出警告,以及 "@on
",以(重新)開始發出;它將忽略未知的控制消息。
xpcall (f, msgh [, arg1, ···])
這個函數與 pcall
相似,唯一不同的是它設置了一個新的消息處理器 msgh
。
這個庫包含了操作協程的方法,它們存放在表 coroutine
內。參見 §2.6 以獲得協程的一般描述。
coroutine.close (co)
關閉協程 co
,即關閉所有待關閉的變數並將協程設置為死狀態。給定的協程必須為死狀態或掛起狀態。如果出現錯誤(無論是停止協程的原始錯誤還是關閉方法中的錯誤),則返回 false 加上錯誤對象;否則返回 true。
coroutine.create (f)
創建一個新的協程,其主體為 f
。 f
必須是一個函數。返回這個新的協程,一個類型為 "thread"
的對象。
coroutine.isyieldable ([co])
當協程 co
可以進行 yield 操作時返回 true。如果未指定 co
,則默認為運行中的協程。
如果協程不是主線程且不在不可進行 yield 的 C 函數中,則該協程可以進行 yield。
coroutine.resume (co [, val1, ···])
啟動或繼續執行協程 co
。第一次恢復協程時,它會開始運行其主體。值 val1
,... 作為參數傳遞給主體函數。如果協程已經進行了 yield,則 resume
會重新啟動它;值 val1
,... 將作為 yield 操作返回的結果進行傳遞。
如果協程在沒有任何錯誤的情況下運行,則 resume
返回 true 加上由 yield
傳遞的任何值(當協程進行 yield 時),或由主體函數返回的任何值(當協程終止時)。如果出現任何錯誤,resume
返回 false 加上錯誤消息。
coroutine.running ()
返回正在運行的協程以及一個布爾值,當正在運行的協程是主協程時返回 true。
coroutine.status (co)
返回協程 co
的狀態,作為一個字符串:如果協程正在運行(即調用 status
的協程),則返回 "running"
;如果協程在調用 yield
時掛起,或者尚未開始運行,則返回 "suspended"
;如果協程是活動的但不在運行(即它已經恢復了另一個協程),則返回 "normal"
;如果協程已完成其主體函數,或者由於錯誤而停止,則返回 "dead"
。
coroutine.wrap (f)
創建一個新的協程,其內容為 f
;f
必須是一個函數。返回一個函數,每次調用該函數時都會恢復協程。傳遞給此函數的任何參數都將作為額外的參數傳遞給 resume
。該函數返回與 resume
返回的相同值,除了第一個布爾值。如果出現錯誤,該函數將關閉協程並傳播錯誤。
coroutine.yield (···)
暫停調用協程的執行。將任何 yield
的參數作為額外的結果傳遞給 resume
。
包裝庫提供了在 Lua 中加載模組的基本設施。它在全局環境中直接導出一個函數:require
。其他所有內容都導出到表 package
中。
require (modname)
加載給定的模組。該函數首先查找 package.loaded
表,以確定 modname
是否已經加載。如果是,則 require
返回存儲在 package.loaded[modname]
中的值。(在這種情況下,缺少第二個結果表示此調用無需加載模組。)否則,它會嘗試查找模組的 加載器。
為了找到一個加載器,require
會參考表 package.searchers
。該表中的每個項目都是一個搜索函數,以特定的方式搜索模組。通過更改此表,我們可以改變 require
查找模組的方式。以下解釋基於默認配置的 package.searchers
。
首先,require
查詢 package.preload[modname]
。如果它有值,則該值(必須是一個函數)是加載器。否則,require
使用存儲在 package.path
中的路徑查找 Lua 加載器。如果這也失敗了,則它使用存儲在 package.cpath
中的路徑查找 C 加載器。如果這也失敗了,則它嘗試一個 一體化 加載器(參見 package.searchers
)。
一旦找到加載器,require
就會使用兩個參數調用該加載器:modname
和一個額外的值,即由搜索器返回的 加載器數據。加載器數據可以是對模組有用的任何值;對於默認搜索器,它表示加載器的位置。 (例如,如果加載器來自文件,則此額外值是文件路徑。)如果加載器返回任何非空值,require
將返回的值賦給 package.loaded[modname]
。如果加載器未返回非空值且未向 package.loaded[modname]
賦值,則 require
將 true 賦給此項目。無論如何,require
都會返回 package.loaded[modname]
的最終值。除了該值,require
還會返回搜索器返回的第二個結果,該結果指示了 require
如何找到模組。
如果模組在載入或執行時出現任何錯誤,或者找不到模組的任何載入器,則 require
會引發錯誤。
package.config
描述某些套件的編譯時配置的字符串。 這個字符串是一系列行
\
'(Windows)和 '/
'(其他系統)。;
'。?
'。!
'。luaopen_
函數名稱時忽略其後所有文本的標記。默認為 '-
'。
package.cpath
一個字符串,指定 require
用於搜索 C 加載器的路徑。
Lua 以與初始化 Lua 路徑 package.path
相同的方式初始化 C 路徑 package.cpath
,使用環境變量 LUA_CPATH_5_4
,或環境變量 LUA_CPATH
,或在 luaconf.h
中定義的默認路徑。
package.loaded
require
用來控制已經載入哪些模組的表格。當你需要一個模組 modname
且 package.loaded[modname]
不為 false 時,require
簡單地返回那裡存儲的值。
這個變量僅是對真實表格的引用;對這個變量的賦值不會更改 require
使用的表格。真實表格存儲在 C 註冊表中(參見 §4.3),索引為鍵 LUA_LOADED_TABLE
,一個字符串。
package.loadlib (libname, funcname)
將主機程序動態連接到 C 庫 libname
。
如果 funcname
是 "*
",則它僅連接到庫,使庫導出的符號對其他動態連接的庫可用。否則,它尋找庫中的一個名為 funcname
的函數,並將此函數作為 C 函數返回。因此,funcname
必須遵循 lua_CFunction
原型(參見 lua_CFunction
)。
這是一個低階功能。它完全繞過了套件和模塊系統。不像 require
,它不執行任何路徑搜索,也不自動添加擴展名。 libname
必須是 C 函式庫的完整文件名,必要時包括路徑和擴展名。 funcname
必須是 C 函式庫導出的確切名稱(這可能取決於所使用的 C 編譯器和鏈接器)。
這個功能不受 ISO C 支持。因此,它僅在某些平台上可用(Windows、Linux、Mac OS X、Solaris、BSD,以及支持 dlfcn
標準的其他 Unix 系統)。
此功能固有地不安全,因為它允許 Lua 調用系統中任何可讀的動態庫中的任何函式。(Lua 調用任何函式,假設該函式具有適當的原型並遵守適當的協議(參見 lua_CFunction
)。因此,調用系統中任意動態庫中的任意函式往往會導致訪問違例。)
package.path
一個字符串,其中包含 require
用於搜索 Lua 加載器的路徑。
在啟動時,Lua 會將此變量初始化為環境變量 LUA_PATH_5_4
或環境變量 LUA_PATH
的值,或者如果這些環境變量未定義,則使用在 luaconf.h
中定義的默認路徑。 環境變量的值中的 ";;
" 會被默認路徑替換。
package.preload
用於存儲特定模塊加載器的表(參見 require
)。
此變量僅是對實際表的引用;對此變量的分配不會更改由 require
使用的表。 實際表存儲在 C 注冊表中(參見 §4.3),索引鍵為 LUA_PRELOAD_TABLE
,一個字符串。
package.searchers
require
使用的表,用於控制如何查找模塊。
這個表中的每個項目都是一個搜索器函數。在尋找模塊時,require
會按升序調用這些搜索器,並將模塊名稱(傳給require
的參數)作為唯一參數。如果搜索器找到了模塊,它將返回另一個函數,即模塊加載器,以及一個額外的值,即加載器數據,該值將作為第二個結果被傳遞給該加載器並由require
返回。如果它找不到模塊,它將返回一個解釋為什麼的字符串(或者如果它沒有任何內容,則返回nil)。
Lua使用四個搜索器函數初始化這個表。
第一個搜索器簡單地在package.preload
表中尋找加載器。
第二個搜索器作為Lua庫尋找加載器,使用存儲在package.path
中的路徑。搜索按照函數package.searchpath
中描述的方式進行。
第三個搜索器作為C庫尋找加載器,使用變量package.cpath
給出的路徑。同樣,搜索按照函數package.searchpath
中描述的方式進行。例如,如果C路徑是字符串
"./?.so;./?.dll;/usr/local/?/init.so"
對於模塊foo
的搜索器將嘗試打開文件./foo.so
、./foo.dll
和/usr/local/foo/init.so
,按照這個順序。一旦找到一個C庫,這個搜索器首先使用動態鏈接工具將應用程序與庫進行鏈接。然後它嘗試在庫中找到一個C函數,用作加載器。這個C函數的名稱是字符串"luaopen_
"與模塊名的副本連接起來,其中每個點被下劃線替換。此外,如果模塊名帶有連字符,則在第一個連字符之後(包括連字符本身)的後綴將被刪除。例如,如果模塊名是a.b.c-v2.1
,則函數名將是luaopen_a_b_c
。
第四個搜索器嘗試一個全功能加載器。它在C路徑中為給定模塊的根名稱搜索庫。例如,當需要a.b.c
時,它將搜索a
的C庫。如果找到,它將在其中查找子模塊的打開函數;在我們的示例中,這將是luaopen_a_b_c
。使用這個功能,一個包可以將多個C子模塊打包到一個單一的庫中,每個子模塊保持其原始的打開函數。
除了第一個搜索器(preload)之外,所有搜索器都將模塊被找到的文件路徑作為額外的值返回,這個值由package.searchpath
返回。第一個搜索器總是返回字符串":preload:
"。
搜尋器在 Lua 中不應該產生錯誤,並且不應該具有任何副作用。(它們在 C 中可能具有副作用,例如通過將應用程式與庫進行連接。)
package.searchpath (name, path [, sep [, rep]])
在給定的路徑中搜尋給定的 name
。
路徑是包含一系列以分號分隔的 模板 的字串。對於每個模板,函數將模板中的每個問號(如果有的話)替換為 name
的副本,在副本中所有 sep
(默認情況下為句點)的出現都替換為 rep
(默認情況下為系統的目錄分隔符號),然後嘗試打開結果的文件名。
例如,如果路徑是字串
"./?.lua;./?.lc;/usr/local/?/init.lua"
對於名稱 foo.a
的搜索將嘗試打開文件 ./foo/a.lua
、./foo/a.lc
和 /usr/local/foo/a/init.lua
,按照這個順序。
返回它可以以讀模式打開的第一個文件的結果名稱(在關閉文件後),或者是 失敗 加上一條錯誤消息,如果沒有成功。 (此錯誤消息列出了它嘗試打開的所有文件名。)
此庫提供了用於字串操作的通用函數,例如查找和提取子字串,以及模式匹配。在 Lua 中索引字串時,第一個字符的位置是 1(不像在 C 中是 0)。允許對索引使用負值,並且將其解釋為從字串末尾開始索引,從末尾的位置開始。因此,最後一個字符位於位置 -1,依此類推。
字串庫將其所有函數都放在表 string
中。它還為字串設置了一個元表,其中 __index
字段指向 string
表。因此,您可以以面向對象的方式使用字串函數。例如,string.byte(s,i)
可以寫成 s:byte(i)
。
字串庫假設單字節字符編碼。
string.byte (s [, i [, j]])
s[i]
、s[i+1]
、...、s[j]
的內部數字代碼。 i
的默認值是 1; j
的默認值是 i
。 這些索引按照函數 string.sub
的相同規則進行了校正。
數字代碼在不同平台上不一定可移植。
string.char (···)
數字代碼在不同平台上不一定可移植。
string.dump (function [, strip])
返回包含给定函数的二进制表示(一个二进制块)的字符串,以便稍后在此字符串上进行的load
返回函数的副本(但具有新的上值)。如果strip
为真值,则二进制表示可能不包括有关函数的所有调试信息,以节省空间。
具有上值的函数仅保存它们的上值数量。重新加载时,这些上值将接收新的实例。(有关这些上值如何初始化的详细信息,请参阅load
函数。您可以使用调试库以适合您需求的方式对函数的上值进行序列化和重新加载。)
string.find (s, pattern [, init [, plain]])
在字符串s
中查找pattern
(参见§6.4.1)的第一个匹配项。如果找到匹配项,则find
返回此出现的起始索引和结束索引;否则,返回fail。第三个可选的数值参数init
指定从哪里开始搜索;其默认值为1,可以为负值。第四个可选参数plain
为true时关闭模式匹配功能,因此函数执行普通的“查找子字符串”操作,pattern
中的字符不被视为特殊字符。
如果模式有捕获,则在成功匹配后,两个索引之后还会返回捕获的值。
string.format (formatstring, ···)
返回其变量数量的格式化版本,遵循其第一个参数中给出的描述,该参数必须是一个字符串。格式字符串遵循与ISO C函数sprintf
相同的规则。唯一的区别是不支持转换说明符和修饰符F
、n
、*
、h
、L
和l
,并且有一个额外的说明符q
。当存在时,宽度和精度都限制为两位数字。
说明符q
以Lua源代码中的有效常量格式化布尔值、nil、数字和字符串。布尔值和nil以明显的方式编写(true
、false
、nil
)。浮点数以十六进制编写,以保留完整的精度。字符串在双引号之间编写,必要时使用转义序列确保可以安全地被Lua解释器读取回来。例如,调用
string.format('%q', 'a string with "quotes" and \n new line')
可能產生字串
"a string with \"quotes\" and \ new line"
此指定符不支援修改器(旗標、寬度、精度)。
轉換指定符 A
、a
、E
、e
、f
、G
和 g
都期望一個數字作為引數。指定符 c
、d
、i
、o
、u
、X
和 x
期望一個整數。當 Lua 與 C89 編譯器一起編譯時,指定符 A
和 a
(十六進制浮點數)不支援修改器。
指定符 s
期望一個字串;如果其引數不是字串,則按照 tostring
的相同規則將其轉換為一個字串。如果指定符有任何修改器,則對應的字串引數不應該包含嵌入的零。
指定符 p
格式化由 lua_topointer
返回的指標。這為表、用戶數據、線程、字串和函數提供了一個唯一的字符串標識符。對於其他值(數字、nil、布爾值),此指定符導致一個代表指針 NULL
的字符串。
string.gmatch (s, 模式 [, 初始值])
s
中的 模式
(參見 §6.4.1)中返回下一個捕獲。如果 模式
指定沒有捕獲,則在每次調用中產生整個匹配。第三個可選的數值引數 初始值
指定從哪裡開始搜索;其默認值為 1,可以為負數。
例如,以下循環將迭代字符串 s
中的所有單詞,每行打印一個
s = "hello world from Lua" for w in string.gmatch(s, "%a+") do print(w) end
下一個示例將從給定字符串中收集所有的 key=value
對到一個表中
t = {} s = "from=world, to=Lua" for k, v in string.gmatch(s, "(%w+)=(%w+)") do t[k] = v end
對於這個函數,模式開頭的插入符 '^
' 不起作用作為錨點,因為這將阻止迭代。
string.gsub (s, 模式, 替換物 [, n])
s
的副本,其中所有(或前 n
個,如果給定)出現的 模式
(參見 §6.4.1)都已被替換為由 替換物
指定的替換字串,它可以是一個字符串、一個表格或一個函數。 gsub
還返回其第二個值,即發生的匹配總數。名稱 gsub
來自於 Global SUBstitution(全局替換)。
如果 替換物
是一個字符串,則其值將用於替換。字符 %
作為轉義字符: 替換物
中形如 %d
(其中 d 在 1 到 9 之間)的序列代表第 d 個捕獲的子字串的值;序列 %0
代表整個匹配;序列 %%
代表單個 %
。
如果 repl
是一個表格,那麼將使用第一個捕獲作為鍵來查詢該表格的每個匹配項目。
如果 repl
是一個函數,則每次匹配發生時,都會調用此函數,並將所有捕獲的子字符串按順序作為參數傳遞。
無論如何,如果模式未指定捕獲,則其行為就像整個模式都在一個捕獲內。
如果表格查詢或函數調用返回的值是字符串或數字,則將其用作替換字符串;否則,如果它是 false 或 nil,則沒有替換(即保留原始匹配項目在字符串中)。
這裡有一些示例
x = string.gsub("hello world", "(%w+)", "%1 %1") --> x="hello hello world world" x = string.gsub("hello world", "%w+", "%0 %0", 1) --> x="hello hello world" x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1") --> x="world hello Lua from" x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv) --> x="home = /home/roberto, user = roberto" x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s) return load(s)() end) --> x="4+5 = 9" local t = {name="lua", version="5.4"} x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t) --> x="lua-5.4.tar.gz"
string.len (s)
接收一個字符串並返回其長度。空字符串 ""
的長度為 0。嵌入的零被計算在內,所以 "a\000bc\000"
的長度為 5。
string.lower (s)
接收一個字符串並返回此字符串的副本,其中所有大寫字母都更改為小寫字母。所有其他字符保持不變。大寫字母的定義取決於當前的區域設置。
string.match (s, pattern [, init])
在字符串 s
中尋找模式(參見 §6.4.1)的第一個匹配項目。如果找到一個,則 match
返回模式的捕獲項目;否則返回 fail。如果 pattern
未指定捕獲,則返回整個匹配項目。第三個可選的數值參數 init
指定從哪裡開始搜索;其默認值為 1,可以是負數。
string.pack (fmt, v1, v2, ···)
返回一個包含值 v1
、v2
等序列化為二進制形式(打包)的二進制字符串,根據格式字符串 fmt
(參見 §6.4.2)。
string.packsize (fmt)
返回給定格式的 string.pack
生成的字符串的長度。格式字符串不能具有變長選項 's
' 或 'z
'(參見 §6.4.2)。
string.rep (s, n [, sep])
返回一個字符串,其中包含由字符串 s
的 n
個副本連接而成,並以字符串 sep
分隔。 sep
的默認值為空字符串(即無分隔符)。如果 n
不是正數,則返回空字符串。
(請注意,只需一次調用此函數就很容易耗盡機器的內存。)
string.reverse (s)
傳回一個反轉的字串,其內容為字串 s
的反轉。
string.sub (s, i [, j])
傳回字串 s
從位置 i
到位置 j
的子字串;i
和 j
可為負數。若省略 j
,則預設為 -1(即與字串長度相同)。特別地,呼叫 string.sub(s,1,j)
則傳回長度為 j
的字串前綴,而對於正數的 i
,string.sub(s, -i)
則傳回長度為 i
的字串後綴。
若經過負索引轉換後,i
小於 1,則會被更正為 1。若 j
大於字串長度,則會被更正為該長度。若經過這些更正後,i
仍大於 j
,則該函式傳回空字串。
string.unpack (fmt, s [, pos])
根據格式字串 fmt
(參見§6.4.2)傳回字串 s
(參見string.pack
)中打包的值。選擇性的 pos
標示從何處開始在 s
中讀取(預設為 1)。在讀取值後,此函式還會傳回 s
中第一個未讀取位元組的索引。
string.upper (s)
接收一個字串並傳回此字串的副本,其中所有小寫字母都轉換為大寫。所有其他字元保持不變。小寫字母的定義取決於當前的語言環境。
在 Lua 中,模式由正規字串描述,這些字串由模式匹配函式 string.find
、string.gmatch
、string.gsub
和 string.match
解釋為模式。本節描述這些字串的語法和意義(即它們匹配的內容)。
字元類別用於表示一組字元。以下組合可用於描述字元類別:
^$()%.[]*+-?
)表示字元 x 本身。
.
: (一個點)表示所有字元。%a
: 表示所有字母。%c
: 代表所有控制字符。%d
: 代表所有數字。%g
: 代表所有可列印字符,但不包括空格。%l
: 代表所有小寫字母。%p
: 代表所有標點符號。%s
: 代表所有空白字符。%u
: 代表所有大寫字母。%w
: 代表所有字母和數字字符。%x
: 代表所有十六進制數字。%x
: (其中x是任意非字母數字符號)代表字元x。這是逃脫魔法字符的標準方式。任何非字母數字符號(包括所有標點符號,即使不是魔法的)都可以在模式中前置'%
'以表示自己。
[set]
: 代表所有set中的字符的聯集。可以通過用一個'-'將範圍的結束字符(按升序排列)分隔開來來指定一個字符範圍。所有上述描述的%
x類也可以用作set中的組件。set中的所有其他字符表示它們自己。例如,[%w_]
(或[_%w]
)表示所有字母和數字字符加上底線,[0-7]
表示八進制數字,[0-7%l%-]
表示八進制數字加上小寫字母加上'-'字符。
您可以通過將其放在集合中的第一個字符位置來將右方括號放在一個集合中。您可以通過將其放在集合中的第一個或最後一個字符位置來將連字符放在一個集合中。(您也可以對這兩種情況使用轉義。)
範圍和類之間的交互作用未定義。因此,像[%a-z]
或[a-%%]
這樣的模式無意義。
[^set]
: 代表set的補集,其中set的解釋如上。
對於由單個字母表示的所有類(%a
、%c
等),相應的大寫字母表示該類的補集。例如,%S
代表所有非空格字符。
字母、空格和其他字符組的定義取決於當前的語言環境。特別地,類[a-z]
可能與%l
不等價。
一個模式項可以是
*
',可匹配類別中零個或多個字符的序列。這些重複項將始終匹配最長可能的序列;
+
',可匹配類別中一個或多個字符的序列。這些重複項將始終匹配最長可能的序列;
-
',也可匹配類別中零個或多個字符的序列。與 '*
' 不同,這些重複項將始終匹配最短可能的序列;
?
',可匹配類別中字符的零個或一個出現。如果可能,它始終匹配一次出現;
%n
,其中 n 在 1 到 9 之間;此類項匹配與第 n 個捕獲的字符串相等的子字符串(見下文);
%bxy
,其中 x 和 y 是兩個不同的字符;此類項匹配以 x 開始,以 y 結束的字符串,並且其中的 x 和 y 是 平衡的。這意味著,如果從左到右讀取字符串,在遇到 x 時計數加 1,在遇到 y 時計數減 1,則結尾的 y 是第一個計數達到 0 的 y。例如,項目 %b()
匹配具有平衡括號的表達式。
%f[set]
,一個 frontier pattern;此類項在任何位置匹配空字符串,使得下一個字符屬於 set,且上一個字符不屬於 set。集合 set 的解釋如前所述。主題的開始和結束被處理為字符 '\0
'。
一個 pattern 是一系列的模式項。在模式開頭的插入符 '^
' 將匹配鏈接到主題字符串的開頭。在模式結尾的 '$
' 將匹配鏈接到主題字符串的結尾。在其他位置,'^
' 和 '$
' 沒有特殊含義,代表它們自己。
模式可以包含括號括起來的子模式;它們描述 captures。當匹配成功時,主題字符串中與捕獲匹配的子字符串將被存儲(captured)以供將來使用。捕獲按照它們的左括號編號。例如,在模式 "(a*(.)%w(%s*))"
中,與字符串匹配的部分 "a*(.)%w(%s*)"
將作為第一個捕獲存儲,因此其編號為 1;與 ".
" 匹配的字符將以編號 2 捕獲,與 "%s*
" 匹配的部分將以編號 3 捕獲。
作為一個特例,捕獲器()
捕獲當前的字符串位置(一個數字)。例如,如果我們對字符串"flaaap"
應用模式"()aa()"
,將會有兩個捕獲:3和5。
函數string.gsub
和迭代器string.gmatch
在主題中匹配給定模式的多個出現。對於這些函數,僅當新匹配至少在上一個匹配的結尾一個字節之後才被認為是有效的。換句話說,模式機器永遠不會接受空字符串作為另一個匹配的立即結果。例如,考慮以下代碼的結果
> string.gsub("abc", "()a*()", print); --> 1 2 --> 3 3 --> 4 4
第二和第三個結果來自於 Lua 在 'b
'後面匹配到一個空字符串,並在 'c
'後面再次匹配到一個空字符串。Lua 不會在 'a
'後面匹配到一個空字符串,因為它會在與上一個匹配的位置相同的位置結束。
string.pack
、string.packsize
和string.unpack
的第一個參數是一個格式字符串,它描述了要創建或讀取的結構的布局。
格式字符串是一系列的轉換選項。轉換選項如下
<
: 設置為小端>
: 設置為大端=
: 設置為本機端![n]
: 將最大對齊設置為n
(默認是本機對齊)b
: 一個有符號的字節(char
)B
: 一個無符號的字節(char
)h
: 一個有符號的short
(本機大小)H
: 一個無符號的short
(本機大小)l
: 一個有符號的long
(本機大小)L
: 一個無符號的long
(本機大小)j
: 一個lua_Integer
J
: 一個lua_Unsigned
T
: 一個size_t
(本機大小)i[n]
: 一個有n
字節的有符號的int
(默認是本機大小)I[n]
: 一個有n
字節的無符號的int
(默認是本機大小)f
: 一個float
(本機大小)d
: 一個double
(本機大小)n
: 一個lua_Number
cn
: 一個具有n
字節的固定大小字符串z
: 一個以零結尾的字符串s[n]
: 一個以其長度編碼的字符串,其長度以一個無符號整數表示,該整數由 n
個字節組成(默認為一個 size_t
)x
: 一個字節的填充Xop
: 一個空項,其對齊方式根據選項 op
而定(否則忽略該選項)
': (空格)被忽略
("[n]
" 表示一個可選的整數。)除填充、空格和配置(選項 "xX <=>!
")外,每個選項對應於 string.pack
中的一個參數或 string.unpack
中的一個結果。
對於選項 "!n
", "sn
", "in
", 和 "In
", n
可以是介於 1 和 16 之間的任意整數。所有整數選項均檢查溢出;string.pack
檢查給定值是否符合給定大小;string.unpack
檢查讀取的值是否符合 Lua 整數。對於無符號選項,Lua 整數也被視為無符號值。
任何格式字符串都可以開始,就好像前面加了 "!1=
" 一樣,即最大對齊為 1(無對齊)且本機字節序。
本機字節序假定整個系統是大端或小端。打包函數將無法正確模擬混合字節序格式的行為。
對齊工作如下:對於每個選項,格式會額外填充,直到數據開始的偏移量為選項大小和最大對齊之間的最小值的倍數;這個最小值必須是 2 的冪。選項 "c
" 和 "z
" 不對齊;選項 "s
" 遵循其開始整數的對齊。
所有填充均由 string.pack
填充為零並被 string.unpack
忽略。
此庫提供對 UTF-8 編碼的基本支援。它將所有功能提供在表 utf8
內。此庫不提供任何有關 Unicode 的支援,僅處理編碼的處理。任何需要字符意義的操作,如字符分類,都不在其範圍內。
除非另有說明,否則所有期望字節位置作為參數的函數都假設給定的位置是字節序列的開始或主題字符串的長度加一。與字符串庫一樣,負索引從字符串的末尾計數。
創建字節序列的函數接受所有值,直到 0x7FFFFFFF
,如原始 UTF-8 規範中所定義的;這意味著最多六個字節的字節序列。
解釋字節序列的函數僅接受有效序列(格式良好且不過長)。默認情況下,它們僅接受導致有效 Unicode 代碼點的字節序列,拒絕大於 10FFFF
和代理。一個布爾參數 lax
,在可用時,取消這些檢查,以便接受所有值直到 0x7FFFFFFF
。(不格式良好和過長的序列仍然被拒絕。)
utf8.char (···)
接收零個或多個整數,將每個整數轉換為對應的UTF-8字節序列,並返回包含所有這些序列的字符串。
utf8.charpattern
模式(一個字符串,不是一個函數)"[\0-\x7F\xC2-\xFD][\x80-\xBF]*
"(參見§6.4.1),匹配一個UTF-8字節序列,假設主題是一個有效的UTF-8字符串。
utf8.codes (s [, lax])
返回值,使構造
for p, c in utf8.codes(s) do body end
將遍歷字符串s
中的所有UTF-8字符,p
是每個字符的位置(以字節為單位),c
是每個字符的代碼點。如果遇到任何無效的字節序列,它會引發錯誤。
utf8.codepoint (s [, i [, j [, lax]]])
返回s
中從字節位置i
到j
(包括兩者)之間開始的所有字符的代碼點(作為整數)。對於i
,默認值是1,對於j
,默認值是i
。如果遇到任何無效的字節序列,它會引發錯誤。
utf8.len (s [, i [, j [, lax]]])
返回字符串s
中在位置i
和j
之間(兩者都包括在內)開始的UTF-8字符數。對於i
,默認值是1,對於j
,默認值是-1。如果找到任何無效的字節序列,則返回fail加上第一個無效字節的位置。
utf8.offset (s, n [, i])
返回s
的第n
個字符(從位置i
計數)的編碼開始的位置(以字節為單位)。負數n
得到位置i
之前的字符。當n
是非負數時,i
的默認值為1,否則為#s + 1
,因此utf8.offset(s, -n)
從字符串結尾的第n
個字符的偏移量。如果指定的字符既不在主題中也不緊挨著其結尾,則該函數返回fail。
作為一個特殊情況,當n
為0時,該函數返回包含s
的第i
個字節的字符的編碼開始。
此函數假設s
是一個有效的UTF-8字符串。
此庫提供了用於表操作的通用函數。它將所有函數放在表table
內。
請記住,每當操作需要表格的長度時,所有有關長度運算符的注意事項都適用(見§3.4.7)。所有函數都會忽略給定為參數的表格中的非數字鍵。
table.concat (list [, sep [, i [, j]]])
給定一個所有元素都是字符串或數字的列表,返回字符串list[i]..sep..list[i+1] ··· sep..list[j]
。參數sep
的默認值是空字符串,i
的默認值是1,j
的默認值是#list
。如果i
大於j
,則返回空字符串。
table.insert (list, [pos,] value)
在list
中的位置pos
插入元素value
,將元素list[pos], list[pos+1], ···, list[#list]
向上移動。參數pos
的默認值是#list+1
,這樣一個調用table.insert(t,x)
就會將x
插入到列表t
的末尾。
table.move (a1, f, e, t [,a2])
將表格a1
中的元素移動到表格a2
中,執行以下多重賦值的等效操作:a2[t],··· = a1[f],···,a1[e]
。參數a2
的默認值是a1
。目標範圍可以與源範圍重疊。要移動的元素數必須適合Lua整數。
返回目標表格a2
。
table.pack (···)
返回一個新表格,其中所有參數都存儲在鍵1、2等中,並帶有一個字段"n
",其中包含參數的總數。請注意,結果表可能不是一個序列,如果一些參數是nil。
table.remove (list [, pos])
從list
中刪除位置pos
的元素,並返回被刪除元素的值。當pos
是介於1和#list
之間的整數時,它會將元素list[pos+1], list[pos+2], ···, list[#list]
向下移動並刪除元素list[#list]
;索引pos
也可以是0,當#list
為0時,或#list + 1
。
參數pos
的默認值是#list
,所以調用table.remove(l)
將刪除列表l
的最後一個元素。
table.sort (list [, comp])
按給定的順序就地對列表元素進行排序,從list[1]
到list[#list]
。如果給定了comp
,則它必須是一個接受兩個列表元素並在最終排序中第一個元素應該出現在第二個元素之前時返回true的函數,以便在排序後,i <= j
意味著not comp(list[j],list[i])
。如果未給定comp
,則使用標準Lua運算符<
。
comp
函數必須定義一個一致的順序;更正式地說,函數必須定義一個嚴格弱順序。(弱順序類似於總順序,但它可以將不同的元素等價於比較目的。)
排序算法不穩定:按給定順序相等的不同元素可能會因排序而改變其相對位置。
table.unpack (list [, i [, j]])
返回给定列表中的元素。此函数等效于
return list[i], list[i+1], ···, list[j]
默认情况下,i
为 1,j
为 #list
。
此庫提供基本的數學函數。它將所有函數和常量置於表格math
內。具有標注 "integer/float
" 的函數對於整數參數給出整數結果,對於非整數參數給出浮點結果。捨入函數math.ceil
、math.floor
和math.modf
在結果在整數範圍內時返回整數,否則返回浮點數。
math.abs (x)
返回 x
和 -x
之間的最大值。 (整數/浮點數)
math.acos (x)
返回 x
的反余弦值 (以弧度為單位)。
math.asin (x)
返回 x
的反正弦值 (以弧度為單位)。
math.atan (y [, x])
返回 y/x
的反正切值 (以弧度為單位),使用兩個參數的符號找到結果的象限。它也正確處理 x
為零的情況。
對於 x
的默認值為 1,這樣調用 math.atan(y)
就會返回 y
的反正切值。
math.ceil (x)
返回大於或等於 x
的最小整數值。
math.cos (x)
返回 x
的餘弦值 (假設 x
單位為弧度)。
math.deg (x)
將角度 x
從弧度轉換為度數。
math.exp (x)
返回值 ex (其中 e
是自然對數的底數)。
math.floor (x)
返回小於或等於 x
的最大整數值。
math.fmod (x, y)
返回 x
除以 y
的餘數,並使商向零捨入。 (整數/浮點數)
math.huge
浮點值 HUGE_VAL
,大於任何其他數值。
math.log (x [, base])
返回以給定底數 base
的對數 x
。 base
的默認值為 e (這樣函數返回 x
的自然對數)。
math.max (x, ···)
根據 Lua 運算符 <
返回具有最大值的參數。
math.maxinteger
math.min (x, ···)
根據 Lua 運算子 <
返回最小值的參數。
math.mininteger
math.modf (x)
返回 x
的整數部分和小數部分。其第二個結果始終是浮點數。
math.pi
π 的值。
math.rad (x)
將角度 x
從度轉換為弧度。
math.random ([m [, n]])
沒有參數調用時,返回在範圍 [0,1) 內均勻分佈的虛擬隨機浮點數。當使用兩個整數 m
和 n
調用時,math.random
返回在範圍 [m, n] 內均勻分佈的虛擬隨機整數。對於正數 n
的調用 math.random(n)
,等效於 math.random(1,n)
。調用 math.random(0)
生成一個所有位(虛擬)隨機的整數。
此函數使用 xoshiro256**
算法生成虛擬隨機 64 位整數,這些整數是使用參數 0 調用的結果。其他結果(範圍和浮點數)從這些整數中無偏差地提取。
Lua 使用等效於不帶參數調用的 math.randomseed
來初始化其虛擬隨機生成器,因此 math.random
應該在每次運行程序時生成不同的結果序列。
math.randomseed ([x [, y]])
至少帶有一個參數調用時,整數參數 x
和 y
將結合為用於重新初始化虛擬隨機生成器的 128 位 種子;相同的種子將生成相同的數字序列。 y
的默認值為零。
不帶參數調用時,Lua 生成一個具有弱隨機性的種子。
此函數返回實際使用的兩個種子組件,以便再次設置它們以重複序列。
為確保初始狀態具有所需的隨機性(或相反,當調試程序時擁有確定的序列,例如),應該使用顯式參數調用 math.randomseed
。
math.sin (x)
返回 x
的正弦值(假設以弧度為單位)。
math.sqrt (x)
返回 x
的平方根。(您也可以使用表達式 x^0.5
來計算此值。)
math.tan (x)
返回 x
的正切值(假設以弧度為單位)。
math.tointeger (x)
若值 x
可轉換為整數,則返回該整數。否則,返回 fail。
math.type (x)
如果 x
是整數,返回 "integer
";如果是浮點數,返回 "float
";如果 x
不是數字,返回 fail。
math.ult (m, n)
返回一個布林值,只有當整數 m
與整數 n
作為無符號整數比較時 m
在 n
之下時,返回 true。
IO 庫提供兩種不同的文件操作風格。第一種使用隱式文件處理;即,有用於設置默認輸入文件和默認輸出文件的操作,所有輸入/輸出操作都在這些默認文件上進行。第二種風格使用顯式文件處理。
在使用隱式文件處理時,所有操作都由表 io
提供。在使用顯式文件處理時,操作 io.open
返回一個文件處理,然後所有操作都作為文件處理的方法提供。
文件處理的元表提供了 __gc
和 __close
的元方法,在調用時試圖關閉文件。
表 io
也提供了三個預定義的文件處理,具有它們在 C 語言中的通常含義: io.stdin
、io.stdout
和 io.stderr
。IO 庫永遠不會關閉這些文件。
除非另有說明,所有 I/O 函數在失敗時返回 fail,加上作為第二結果的錯誤消息和作為第三結果的系統相關的錯誤碼,在成功時返回一些非偽值。在非 POSIX 系統上,發生錯誤時錯誤消息和錯誤碼的計算可能不是線程安全的,因為它們依賴於全局 C 變量 errno
。
io.close ([file])
等同於 file:close()
。如果沒有 file
,則關閉默認輸出文件。
io.flush ()
等同於 io.output():flush()
。
io.input ([file])
當使用文件名調用時,它打開指定的文件(以文本模式),並將其處理程序設置為默認輸入文件。當使用文件處理調用時,它只是將此文件處理設置為默認輸入文件。沒有參數調用時,它返回當前的默認輸入文件。
在發生錯誤時,此函數引發錯誤,而不是返回錯誤碼。
io.lines ([filename, ···])
以讀取模式打開給定的文件名並返回一個迭代器函數,它的行為類似於 file:lines(···)
在已打開的文件上。當迭代器函數無法讀取任何值時,它會自動關閉文件。除了迭代器函數外,io.lines
還返回三個其他值:兩個 nil 值作為占位符,再加上創建的文件處理。因此,在通用的 for 循環中使用時,如果循環由於錯誤或 break 被中斷,文件也會被關閉。
呼叫io.lines()
(不帶文件名)等同於io.input():lines("l")
;也就是說,它會遍歷默認輸入文件的各行。在這種情況下,迭代器在循環結束時不會關閉文件。
如果打開文件時出現錯誤,此函數將引發錯誤,而不是返回錯誤代碼。
io.open (文件名 [, 模式])
此函數打開一個文件,使用字符串模式
中指定的模式。如果成功,它將返回一個新的文件處理器。
字符串模式
可以是以下任何一種
r
": 讀取模式(默認);w
": 寫入模式;a
": 附加模式;r+
": 更新模式,所有先前的數據都得以保留;w+
": 更新模式,所有先前的數據都將被清除;a+
": 附加更新模式,先前的數據得以保留,只允許在文件末尾寫入。
字符串模式
還可以在末尾帶有'b
',這在一些系統中需要以二進制模式打開文件。
io.output ([文件])
類似於io.input
,但作用於默認的輸出文件。
io.popen (prog [, 模式])
此函數依賴系統並非所有平台都可用。
啟動獨立進程中的程序prog
,並返回一個文件處理器,您可以用來從該程序讀取數據(如果模式
是"r"
,則默認)或將數據寫入該程序(如果模式
是"w"
)。
io.read (···)
等同於io.input():read(···)
。
io.tmpfile ()
如果成功,返回一個臨時文件的處理器。此文件以更新模式打開,並在程序結束時自動刪除。
io.type (對象)
檢查對象
是否是有效的文件處理器。如果對象
是一個打開的文件處理器,則返回字符串"file"
,如果對象
是一個已關閉的文件處理器,則返回"closed file"
,如果對象
不是文件處理器,則返回fail。
io.write (···)
等同於io.output():write(···)
。
文件:close ()
關閉文件
。請注意,當其處理器被垃圾回收時,文件會自動關閉,但這需要不可預測的時間。
當關閉由 io.popen
建立的文件處理程序時,file:close
返回與 os.execute
返回的相同值。
file:flush ()
將任何已寫入的數據保存到 file
中。
file:lines (···)
返回一個迭代器函數,每次調用時,根據給定的格式讀取文件。 當未給定格式時,使用 "l
" 作為默認值。 例如,構造
for c in file:lines(1) do body end
將迭代文件的所有字符,從當前位置開始。 與 io.lines
不同,此函數在循環結束時不會關閉文件。
file:read (···)
根據給定的格式讀取文件 file
,這些格式指定要讀取的內容。 對於每個格式,函數返回一個字符串或一個數字,其中包含讀取的字符,或者 fail 如果它無法使用指定的格式讀取數據。(在這種情況下,函數不會讀取後續格式。)當無參數調用時,它使用一個讀取下一行的默認格式(見下文)。
可用的格式包括
n
": 讀取數字並將其作為 Lua 的浮點數或整數返回,遵循語法規則。 (數字可以有前置空格和符號。)此格式始終讀取最長的輸入序列,該序列是數字的有效前綴; 如果該前綴不構成有效的數字(例如,空字符串、 "0x
" 或 "3.4e-
")或者它太長(超過 200 個字符),則將其丟棄,並且格式返回 fail。
a
": 從當前位置開始讀取整個文件。 在文件結尾時,返回空字符串;此格式永遠不會失敗。
l
": 讀取下一行並跳過行尾,並在文件結尾時返回 fail。 這是默認格式。
L
": 讀取下一行並保留行尾字符(如果存在),並在文件結尾時返回 fail。
number
為零,則不讀取任何內容並返回空字符串,或在文件結尾時返回 fail。
格式 "l
" 和 "L
" 應僅用於文本文件。
file:seek ([whence [, offset]])
設置並獲取文件位置,從文件開頭計算,到由字符串 whence
指定的基底加上位置 offset
,如下
set
": 基底是位置 0(文件開頭);cur
": 基底是當前位置;end
": 基底為檔案結尾;
在成功的情況下,seek
返回從檔案開頭以字節為單位的最終文件位置。如果 seek
失敗,則返回 fail,加上描述錯誤的字符串。
whence
的默認值為 "cur"
,而 offset
的默認值為 0。因此,調用 file:seek()
將返回當前文件位置,而不會更改它; 調用 file:seek("set")
會將位置設置為文件開頭(並返回 0); 而調用 file:seek("end")
會將位置設置為文件末尾,並返回其大小。
file:setvbuf (mode [, size])
為文件設置緩衝模式。有三種可用模式
no
": 不進行緩衝。full
": 完全緩衝。line
": 行緩衝。
對於最後兩種情況,size
是緩衝區大小的提示,以字節為單位。默認值是適當的大小。
每種模式的具體行為不可移植; 請查看您平台上底層 ISO C 函數 setvbuf
的更多細節。
file:write (···)
將其每個參數的值寫入 file
。參數必須是字符串或數字。
在成功的情況下,此函數返回 file
。
此庫通過表格 os
實現。
os.clock ()
返回程序使用的 CPU 時間的近似量,以秒為單位,由底層 ISO C 函數 clock
返回。
os.date ([format [, time]])
返回一個字符串或包含日期和時間的表,格式根據給定的字符串 format
进行。
如果存在 time
參數,則這是要格式化的時間(有關此值的描述,請參見 os.time
函數)。否則,date
格式化當前時間。
如果 format
以 '!
' 開頭,則日期將以協調世界時格式化。在此可選字符之後,如果 format
是字符串 "*t
",則 date
返回具有以下字段的表: year
、month
(1–12)、day
(1–31)、hour
(0–23)、min
(0–59)、sec
(0–61,因閏秒而不同)、wday
(星期幾,1–7,星期日為 1)、yday
(一年中的第幾天,1–366) 和 isdst
(夏令時標誌,布林值)。如果信息不可用,則可能缺少此字段。
如果 format
不是 "*t
",則 date
以字符串形式返回日期,格式與 ISO C 函數 strftime
相同。
如果缺少 format
,則默認為 "%c
",它使用當前區域設置提供人類可讀的日期和時間表示。
在非 POSIX 系統上,由於依賴於 C 函數 gmtime
和 C 函數 localtime
,此函數可能不是線程安全的。
os.difftime (t2, t1)
返回從時間 t1
到時間 t2
(時間由 os.time
返回的值)的差異,以秒為單位。在 POSIX、Windows 和一些其他系統中,此值正好是 t2
-t1
。
os.execute ([command])
此函數等同於 ISO C 函數 system
。它將 command
傳遞給操作系統外殼以執行。它的第一個結果如果命令正常終止則為 true,否則為 fail。在此第一個結果之後,函數返回一個字符串加一個數字,如下所示
exit
": 命令正常終止;以下數字是命令的退出狀態。
signal
": 命令被信號終止;以下數字是終止命令的信號。
如果未帶有 command
調用 os.execute
,則返回一個布林值,如果可用外殼則為 true。
os.exit ([code [, close]])
調用 ISO C 函數 exit
來終止主機程序。如果 code
為 true,則返回狀態為 EXIT_SUCCESS
;如果 code
為 false,則返回狀態為 EXIT_FAILURE
;如果 code
為數字,則返回狀態為該數字。 code
的默認值為 true。
如果可選的第二個參數 close
為 true,則函數在退出之前關閉 Lua 狀態(請參見 lua_close
)。
os.getenv (varname)
返回進程環境變量 varname
的值,如果未定義該變量,則返回 fail。
os.remove (filename)
刪除給定名稱的文件(或在 POSIX 系統上的空目錄)。如果此函數失敗,則返回 fail 以及描述錯誤的字符串和錯誤代碼。否則,返回 true。
os.rename (oldname, newname)
將名為 oldname
的文件或目錄重命名為 newname
。如果此函數失敗,則返回 fail,加上描述錯誤的字符串和錯誤代碼。否則,返回 true。
os.setlocale (locale [, category])
設置程序的當前語言環境。 locale
是一個系統相依的字符串,指定一個語言環境; category
是一個可選的字符串,描述要更改的類別: "all"
、 "collate"
、 "ctype"
、 "monetary"
、 "numeric"
或 "time"
;默認類別是 "all"
。該函數返回新語言環境的名稱,如果無法滿足請求,則返回 fail。
如果 locale
是空字符串,則當前語言環境設置為一個實現定義的本地語言環境。如果 locale
是字符串 "C
",則當前語言環境設置為標準 C 語言環境。
當第一個參數為 nil 時,此函數僅返回給定類別的當前語言環境的名稱。
由於其依賴於 C 函數 setlocale
,此函數可能不是線程安全的。
os.time ([table])
如果不帶參數調用,返回當前時間;如果帶有給定表格,則返回表示該表格指定的本地日期和時間的時間。該表格必須具有字段 year
、 month
和 day
,並且可能具有字段 hour
(默認為 12)、 min
(默認為 0)、 sec
(默認為 0)和 isdst
(默認為 nil)。其他字段將被忽略。有關這些字段的描述,請參見 os.date
函數。
在調用該函數時,這些字段中的值不需要在其有效範圍內。例如,如果 sec
為 -10,則表示比其他字段指定的時間早 10 秒;如果 hour
為 1000,則表示比其他字段指定的時間晚 1000 小時。
返回值是一個數字,其含義取決於您的系統。在 POSIX、Windows 和一些其他系統中,此數字計算自某個給定的起始時間("epoch")以來的秒數。在其他系統中,含義未指定,並且 time
返回的數字僅可用作 os.date
和 os.difftime
的參數。
帶有表格調用時,os.time
還將規範 os.date
函數中記錄的所有字段,以便它們表示調用前的相同時間,但其值在其有效範圍內。
os.tmpname ()
返回一個可用於臨時文件的文件名字符串。在使用之前,必須顯式地打開文件,並在不再需要時明確地刪除它。
在POSIX系統中,此函數還會創建一個帶有該名稱的文件,以避免安全風險。(在獲取名稱和創建文件之間,其他人可能使用錯誤的權限創建文件。)您仍然必須打開文件才能使用它並刪除它(即使您不使用它)。
如果可能,您可以優先使用io.tmpfile
,該函數在程序結束時自動刪除文件。
此庫提供了Lua程序的調試接口(§4.7)的功能。在使用此庫時,應該格外小心。其中的一些功能違反了有關Lua代碼的基本假設(例如,函數內部的局部變量無法從外部訪問;userdata元表無法由Lua代碼更改;Lua程序不會崩潰),因此可能會危及原本安全的代碼。此外,此庫中的某些功能可能速度較慢。
此庫中的所有功能都位於debug
表內。所有作用於線程的功能都有一個可選的第一個參數,該參數是要操作的線程。默認情況下始終為當前線程。
debug.debug ()
與用戶進入交互模式,運行用戶輸入的每個字符串。用戶可以使用簡單的命令和其他調試設施檢查全局和局部變量,更改它們的值,評估表達式等。包含僅包含單詞cont
的行將結束此函數,以便調用者繼續其執行。
請注意,debug.debug
的命令未在任何函數內進行詞法嵌套,因此無法直接訪問局部變量。
debug.gethook ([thread])
返回線程的當前鉤子設置,作為三個值:當前鉤子函數,當前鉤子掩碼和當前鉤子計數,由debug.sethook
函數設置。
如果沒有活動鉤子,則返回fail。
debug.getinfo ([thread,] f [, what])
返回一個包含有關函數的資訊的表格。您可以直接提供函數,也可以將 f
的值設置為一個數字,這意味著該函數在給定線程的呼叫堆疊的第 f
層運行:level 0 是當前函數(getinfo
本身);level 1 是呼叫 getinfo
的函數(尾呼叫除外,在堆疊中不計算);依此類推。如果 f
大於活動函數的數量,則 getinfo
返回 fail。
返回的表格可以包含由 lua_getinfo
返回的所有欄位,其中字串 what
描述要填入的欄位。默認情況下,what
是獲取所有可用的資訊,但不包括有效行的表格。如果存在,選項 'f
' 將添加一個名為 func
的欄位,其中包含函數本身。如果存在,選項 'L
' 將添加一個名為 activelines
的欄位,其中包含有效行的表格。
例如,表達式 debug.getinfo(1,"n").name
如果可以找到合理的名稱,則返回當前函數的名稱,表達式 debug.getinfo(print)
返回一個包含有關 print
函數的所有可用資訊的表格。
debug.getlocal ([thread,] f, local)
此函數返回堆疊上層第 f
層的函數中具有索引 local
的區域變數的名稱和值。此函數不僅訪問顯式區域變數,還訪問參數和臨時值。
第一個參數或區域變數的索引為 1,依此類推,按照它們在代碼中聲明的順序計算,僅計算在函數當前作用域中活動的變數。如果編譯時常量被編譯器優化掉,則可能不會出現在此列表中。負索引指的是可變參數;-1 是第一個可變參數。如果沒有具有給定索引的變數,則函數返回 fail,並在呼叫範圍超出範圍時引發錯誤。 (您可以呼叫 debug.getinfo
檢查級別是否有效。)
以 '(
'(開放括號)開頭的變數名稱表示沒有已知名稱的變數(內部變數,例如循環控制變數,以及保存了無調試信息的塊的變數)。
參數 f
也可以是一個函數。在這種情況下,getlocal
僅返回函數參數的名稱。
debug.getmetatable (value)
返回給定 value
的元表,如果沒有元表則返回 nil。
debug.getregistry ()
返回註冊表(參見 §4.3)。
debug.getupvalue (f, up)
此函數返回函數 f
的索引為 up
的上值的名稱和值。如果沒有給定索引的上值,則返回 fail。
(對於 Lua 函數,上值是函數使用的外部局部變量,因此包含在其閉包中。)
對於 C 函數,此函數使用空字符串 ""
作為所有上值的名稱。
變量名 '?
'(問號)表示沒有已知名稱的變量(保存無調試信息的塊中的變量)。
debug.getuservalue (u, n)
返回與用戶數據 u
關聯的第 n
個用戶值加上一個布爾值,如果用戶數據沒有該值則返回 false。
debug.sethook ([thread,] hook, mask [, count])
將給定的函數設置為調試鉤子。字符串 mask
和數字 count
描述鉤子何時被調用。字符串 mask 可以包含以下任意組合的字符,具有以下含義
c
': 每次 Lua 調用函數時調用鉤子;r
': 每次 Lua 從函數返回時調用鉤子;l
': 每次 Lua 進入新的代碼行時調用鉤子。
此外,如果 count
不為零,則每過 count
條指令後也會調用鉤子。
如果不帶參數調用,則debug.sethook
將關閉鉤子。
當鉤子被調用時,它的第一個參數是描述觸發其調用的事件的字符串:"call"
、"tail call"
、"return"
、"line"
和"count"
。對於行事件,鉤子還會將新的行號作為其第二個參數。在鉤子內部,您可以使用level 2調用getinfo
以獲取有關運行函數的更多信息。(Level 0是getinfo
函數,Level 1是鉤子函數。)
debug.setlocal ([thread,] level, local, value)
此函數將值value
分配給堆棧中level級別處函數的索引為local
的局部變量。如果沒有帶有給定索引的局部變量,該函數返回失敗,並在使用超出範圍的level
時引發錯誤。(您可以調用getinfo
來檢查level是否有效。)否則,它將返回局部變量的名稱。
有關變量索引和名稱的更多信息,請參見debug.getlocal
。
debug.setmetatable (value, table)
將給定的value
的元表設置為給定的table
(可以為nil)。返回value
。
debug.setupvalue (f, up, value)
此函數將值value
分配給函數f
的索引為up
的上值。如果沒有帶有給定索引的上值,該函數返回失敗。否則,它將返回上值的名稱。
有關上值的更多資訊,請參閱debug.getupvalue
。
debug.setuservalue (udata, value, n)
將給定的value
設置為與給定的udata
關聯的第n
個用戶值。 udata
必須是完整的用戶數據。
返回udata
,如果用戶數據不具有該值,則返回失敗。
debug.traceback ([thread,] [message [, level]])
如果message
存在但既不是字符串也不是nil,則此函數將不進行進一步處理,直接返回message
。否則,它將返回一個帶有調用堆棧的跟踪信息的字符串。可選的message
字符串將附加在跟踪信息的開頭。可選的level
數字告訴在哪個級別開始跟踪(默認為1,調用traceback
函數的函數)。
debug.upvalueid (f, n)
返回給定函數的第n
個上值的唯一標識符(作為輕量級用戶數據)。
這些唯一標識符允許程序檢查不同的閉包是否共享上值。對於訪問相同外部本地變量的 Lua 閉包,它們將對這些上值索引返回相同的 id。
debug.upvaluejoin (f1, n1, f2, n2)
使Lua閉包f1
的第n1
個上值參考Lua閉包f2
的第n2
個上值。
雖然 Lua 被設計成一種擴展語言,可以嵌入到主機 C 程式中,但它也常被用作一種獨立的語言。一個獨立的 Lua 解譯器,簡稱為 lua
,隨標準發行版提供。這個獨立解譯器包含所有標準庫。它的用法是
lua [options] [script [args]]
選項包括
-e stat
: 執行字串 stat;-i
: 執行完 script 後進入互動模式;-l mod
: "require" mod 並將結果賦值給全局 mod;-l g=mod
: "require" mod 並將結果賦值給全局 g;-v
: 印出版本信息;-E
: 忽略環境變數;-W
: 打開警告;--
: 停止處理選項;-
: 執行 stdin
作為文件並停止處理選項。
(形式 -l g=mod
在版本 5.4.4 中引入。)
處理完選項後,lua
執行給定的 script。當沒有參數調用時,當標準輸入 (stdin
) 是一個終端時,lua
表現為 lua -v -i
,否則表現為 lua -
。
沒有使用選項 -E
調用時,解譯器在運行任何參數之前會檢查環境變數 LUA_INIT_5_4
(如果未定義版本名稱,則為 LUA_INIT
)。如果變數內容格式為 @filename
,則 lua
執行該文件。否則,lua
執行字串本身。
使用選項 -E
調用時,Lua 不會查詢任何環境變數。特別是,package.path
和 package.cpath
的值會設置為 luaconf.h
中定義的默認路徑。
選項 -e
、-l
和 -W
會按照它們出現的順序進行處理。例如,像這樣調用
$ lua -e 'a=1' -llib1 script.lua
將首先將 a
設置為 1,然後要求庫 lib1
,最後執行沒有參數的文件 script.lua
。 (這裡 $
是 shell 提示符。您的提示符可能不同。)
在運行任何代碼之前,lua
將所有命令行參數收集到一個名為 arg
的全局表中。腳本名稱存放在索引 0,腳本名稱後的第一個參數存放在索引 1,以此類推。腳本名稱之前的任何參數 (即,解譯器名稱加其選項) 存放在負索引中。例如,在以下調用中
$ lua -la b.lua t1 t2
這張表是這樣的
arg = { [-2] = "lua", [-1] = "-la", [0] = "b.lua", [1] = "t1", [2] = "t2" }
如果呼叫中沒有腳本,則解釋器名稱進入索引 0,後面跟著其他參數。例如,調用
$ lua -e "print(arg[1])"
將打印 "-e
"。如果有腳本,則使用參數 arg[1]
, ···,arg[#arg]
調用腳本。像 Lua 中的所有塊一樣,腳本被編譯為一個可變參數函數。
在交互模式下,Lua 會重複提示並等待一行。讀取一行後,Lua 首先嘗試將該行解釋為表達式。如果成功,它將打印其值。否則,它將該行解釋為語句。如果您編寫了一條不完整的語句,解釋器將等待其完成,並發出不同的提示。
如果全局變量 _PROMPT
包含一個字符串,那麼它的值將用作提示。同樣,如果全局變量 _PROMPT2
包含一個字符串,則它的值將用作次要提示(在不完整的語句期間發出)。
在腳本中發生未受保護的錯誤時,解釋器將錯誤報告給標準錯誤流。如果錯誤對象不是字符串,但具有元方法 __tostring
,則解釋器調用此元方法以生成最終消息。否則,解釋器將錯誤對象轉換為字符串並添加堆棧回溯到其中。當警告開啟時,它們僅在標準錯誤輸出中打印。
正常結束時,解釋器將關閉其主要 Lua 狀態(請參見 lua_close
)。腳本可以通過調用 os.exit
來避免此步驟而終止。
為了允許在 Unix 系統中將 Lua 用作腳本解釋器,如果文件塊的第一行以 #
開頭,則 Lua 將跳過該行。因此,可以通過使用 chmod +x
和 #!
形式將 Lua 腳本製作成可執行程序,如下所示
#!/usr/local/bin/lua
當然,Lua 解釋器的位置可能在您的機器上不同。如果 lua
在您的 PATH
中,那麼
#!/usr/bin/env lua
是一個更便攜的解決方案。
在此,我們列出了將程序從 Lua 5.3 移至 Lua 5.4 時可能遇到的不兼容性。
您可以透過使用適當的選項編譯 Lua(請參閱文件luaconf.h
)來避免一些不相容性。然而,所有這些相容性選項將來都會被移除。當這些相容性選項被移除時,通常會出現相容性問題。因此,每當有機會時,您應該嘗試使用所有相容性選項都關閉的 Lua 版本測試您的代碼。這將有助於過渡到更新的 Lua 版本。
Lua 版本始終可以以不會導致程序源代碼更改的方式更改 C API,例如常量的數值或函數的實現方式作為宏。因此,您永遠不應假設不同 Lua 版本之間的二進制文件是相容的。在使用新版本時,總是重新編譯 Lua API 的客戶端。
同樣地,Lua 版本始終可以更改預編譯塊的內部表示形式;預編譯塊在不同的 Lua 版本之間不相容。
官方發行版中的標準路徑在不同版本之間可能會更改。
"1" + "2"
的結果現在是一個整數,而不是浮點數。
__lt
元方法來模擬__le
的用法。在需要時,必須明確定義此元方法。
__gc
元方法。任何值都會被呼叫,如果存在的話(非可呼叫的值會產生警告,就像呼叫終結器時的任何其他錯誤一樣)。
print
不會呼叫 tostring
來格式化其參數;取而代之的是,它已經內建了這個功能。您應該使用 __tostring
來修改值的打印方式。
math.random
使用的偽隨機數生成器現在以一個略微隨機的種子開始。此外,它使用了一個不同的演算法。
utf8
函式庫中的解碼函式不接受代理作為有效的代碼點。這些函式中的額外參數使它們更加寬鬆。
collectgarbage
的選項 "setpause
" 和 "setstepmul
" 已經被棄用。您應該使用新的選項 "incremental
" 來設置它們。
io.lines
現在返回四個值,而不僅僅是一個。這可能在它作為另一個具有可選參數的函式的唯一參數時導致問題,例如在 load(io.lines(filename, "L"))
中。為了解決這個問題,您可以將調用包裝在括號中,將其結果數調整為一個。
lua_newuserdata
、lua_setuservalue
和 lua_getuservalue
被 lua_newuserdatauv
、lua_setiuservalue
和 lua_getiuservalue
取代,它們有一個額外的參數。
出於兼容性考慮,舊名稱仍然作為宏工作,假設只有一個使用者值。但是,具有零個使用者值的使用者數據在記憶體方面更有效率。
lua_resume
有一個額外的參數。這個輸出參數返回在堆棧頂端由協程產生或返回的值的數量(在先前版本中,這些值是整個堆棧)。
lua_version
返回版本號,而不是版本號的地址。Lua 核心應該與使用它們自己的靜態副本的庫一起正常工作,因此不需要檢查它們是否使用相同的地址空間。
LUA_ERRGCMM
被移除了。終結器中的錯誤不會被傳播;相反,它們會生成一個警告。
lua_gc
的選項 LUA_GCSETPAUSE
和 LUA_GCSETSTEPMUL
已被棄用。您應該使用新選項 LUA_GCINC
來設置它們。
這裡是 Lua 的擴展 BNF 完整語法。如同在擴展 BNF 中通常的,{A} 表示 0 或更多個 A,而 [A] 表示可選的 A。(有關運算符優先級,請參見§3.4.8;有關終端符號 Name、Numeral 和 LiteralString 的描述,請參見§3.1。)
chunk ::= block block ::= {stat} [retstat] stat ::= ‘;’ | varlist ‘=’ explist | functioncall | label | break | goto Name | do block end | while exp do block end | repeat block until exp | if exp then block {elseif exp then block} [else block] end | for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end | for namelist in explist do block end | function funcname funcbody | local function Name funcbody | local attnamelist [‘=’ explist] attnamelist ::= Name attrib {‘,’ Name attrib} attrib ::= [‘<’ Name ‘>’] retstat ::= return [explist] [‘;’] label ::= ‘::’ Name ‘::’ funcname ::= Name {‘.’ Name} [‘:’ Name] varlist ::= var {‘,’ var} var ::= Name | prefixexp ‘[’ exp ‘]’ | prefixexp ‘.’ Name namelist ::= Name {‘,’ Name} explist ::= exp {‘,’ exp} exp ::= nil | false | true | Numeral | LiteralString | ‘...’ | functiondef | prefixexp | tableconstructor | exp binop exp | unop exp prefixexp ::= var | functioncall | ‘(’ exp ‘)’ functioncall ::= prefixexp args | prefixexp ‘:’ Name args args ::= ‘(’ [explist] ‘)’ | tableconstructor | LiteralString functiondef ::= function funcbody funcbody ::= ‘(’ [parlist] ‘)’ block end parlist ::= namelist [‘,’ ‘...’] | ‘...’ tableconstructor ::= ‘{’ [fieldlist] ‘}’ fieldlist ::= field {fieldsep field} [fieldsep] field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp fieldsep ::= ‘,’ | ‘;’ binop ::= ‘+’ | ‘-’ | ‘*’ | ‘/’ | ‘//’ | ‘^’ | ‘%’ | ‘&’ | ‘~’ | ‘|’ | ‘>>’ | ‘<<’ | ‘..’ | ‘<’ | ‘<=’ | ‘>’ | ‘>=’ | ‘==’ | ‘~=’ | and | or unop ::= ‘-’ | not | ‘#’ | ‘~’