譯者 云風(fēng)
Lua.org, PUC-Rio 版權(quán)所有 © 2015 , 在遵循 Lua license 條款下,可自由使用。
目錄 · 索引 · 中英術(shù)語對照表
Lua 是一門擴(kuò)展式程序設(shè)計語言,被設(shè)計成支持通用過程式編程,并有相關(guān)數(shù)據(jù)描述設(shè)施。 同時對面向?qū)ο缶幊?、函?shù)式編程和數(shù)據(jù)驅(qū)動式編程也提供了良好的支持。 它作為一個強大、輕量的嵌入式腳本語言,可供任何需要的程序使用。 Lua 由 clean C(標(biāo)準(zhǔn) C 和 C++ 間共通的子集) 實現(xiàn)成一個庫。
作為一門擴(kuò)展式語言,Lua 沒有 "main" 程序的概念:
它只能 嵌入 一個宿主程序中工作,
該宿主程序被稱為 被嵌入程序 或者簡稱 宿主 。
宿主程序可以調(diào)用函數(shù)執(zhí)行一小段 Lua 代碼,可以讀寫 Lua 變量,可以注冊 C 函數(shù)讓 Lua 代碼調(diào)用。
依靠 C 函數(shù),Lua 可以共享相同的語法框架來定制編程語言,從而適用不同的領(lǐng)域。
Lua 的官方發(fā)布版包含一個叫做 lua
的宿主程序示例,
它是一個利用 Lua 庫實現(xiàn)的完整獨立的 Lua 解釋器,可用于交互式應(yīng)用或批處理。
Lua 是一個自由軟件,其使用許可證決定了它的使用過程無需任何擔(dān)保。
本手冊所描述的實現(xiàn)可以在 Lua 的官方網(wǎng)站 www.lua.org
找到。
與其它的許多參考手冊一樣,這份文檔有些地方比較枯燥。 關(guān)于 Lua 背后的設(shè)計思想, 可以看看 Lua 網(wǎng)站上提供的技術(shù)論文。 至于用 Lua 編程的細(xì)節(jié)介紹, 請參閱 Roberto 的書,Programming in Lua。
本章描述了語言的基本概念。
Lua 是一門動態(tài)類型語言。 這意味著變量沒有類型;只有值才有類型。 語言中不設(shè)類型定義。 所有的值攜帶自己的類型。
Lua 中所有的值都是 一等公民。 這意味著所有的值均可保存在變量中、 當(dāng)作參數(shù)傳遞給其它函數(shù)、以及作為返回值。
Lua 中有八種基本類型:
nil、boolean、number、string、function、userdata、
thread 和 table。
Nil 是值 nil 的類型,
其主要特征就是和其它值區(qū)別開;通常用來表示一個有意義的值不存在時的狀態(tài)。
Boolean 是 false 與 true 兩個值的類型。
nil 和 false 都會導(dǎo)致條件判斷為假;
而其它任何值都表示為真。
Number 代表了整數(shù)和實數(shù)(浮點數(shù))。
String 表示一個不可變的字節(jié)序列。
Lua 對 8 位是友好的:
字符串可以容納任意 8 位值,
其中包含零 ('\0
') 。
Lua 的字符串與編碼無關(guān);
它不關(guān)心字符串中具體內(nèi)容。
number 類型有兩種內(nèi)部表現(xiàn)方式,
整數(shù) 和 浮點數(shù)。
對于何時使用哪種內(nèi)部形式,Lua 有明確的規(guī)則,
但它也按需(參見 §3.4.3)作自動轉(zhuǎn)換。
因此,程序員多數(shù)情況下可以選擇忽略整數(shù)與浮點數(shù)之間的差異或者假設(shè)完全控制每個數(shù)字的內(nèi)部表現(xiàn)方式。
標(biāo)準(zhǔn) Lua 使用 64 位整數(shù)和雙精度(64 位)浮點數(shù),
但你也可以把 Lua 編譯成使用 32 位整數(shù)和單精度(32 位)浮點數(shù)。
以 32 位表示數(shù)字對小型機器以及嵌入式系統(tǒng)特別合適。
(參見 luaconf.h
文件中的宏 LUA_32BITS
。)
Lua 可以調(diào)用(以及操作)用 Lua 或 C (參見 §3.4.10)編寫的函數(shù)。 這兩種函數(shù)有統(tǒng)一類型 function。
userdata 類型允許將 C 中的數(shù)據(jù)保存在 Lua 變量中。 用戶數(shù)據(jù)類型的值是一個內(nèi)存塊, 有兩種用戶數(shù)據(jù): 完全用戶數(shù)據(jù) ,指一塊由 Lua 管理的內(nèi)存對應(yīng)的對象; 輕量用戶數(shù)據(jù) ,則指一個簡單的 C 指針。 用戶數(shù)據(jù)在 Lua 中除了賦值與相等性判斷之外沒有其他預(yù)定義的操作。 通過使用 元表 ,程序員可以給完全用戶數(shù)據(jù)定義一系列的操作 (參見 §2.4)。 你只能通過 C API 而無法在 Lua 代碼中創(chuàng)建或者修改用戶數(shù)據(jù)的值, 這保證了數(shù)據(jù)僅被宿主程序所控制。
thread 類型表示了一個獨立的執(zhí)行序列,被用于實現(xiàn)協(xié)程 (參見 §2.6)。 Lua 的線程與操作系統(tǒng)的線程毫無關(guān)系。 Lua 為所有的系統(tǒng),包括那些不支持原生線程的系統(tǒng),提供了協(xié)程支持。
table 是一個關(guān)聯(lián)數(shù)組,
也就是說,這個數(shù)組不僅僅以數(shù)字做索引,除了 nil 和 NaN 之外的所有 Lua 值
都可以做索引。
(Not a Number 是一個特殊的數(shù)字,它用于表示未定義或表示不了的運算結(jié)果,比如 0/0
。)
表可以是 異構(gòu) 的;
也就是說,表內(nèi)可以包含任何類型的值( nil 除外)。
任何鍵的值若為 nil 就不會被記入表結(jié)構(gòu)內(nèi)部。
換言之,對于表內(nèi)不存在的鍵,都對應(yīng)著值 nil 。
表是 Lua 中唯一的數(shù)據(jù)結(jié)構(gòu),
它可被用于表示普通數(shù)組、序列、符號表、集合、記錄、圖、樹等等。
對于記錄,Lua 使用域名作為索引。
語言提供了 a.name
這樣的語法糖來替代
a["name"]
這種寫法以方便記錄這種結(jié)構(gòu)的使用。
在 Lua 中有多種便利的方式創(chuàng)建表(參見 §3.4.9)。
我們使用 序列 這個術(shù)語來表示一個用 {1..n} 的正整數(shù)集做索引的表。 這里的非負(fù)整數(shù) n 被稱為該序列的長度(參見 §3.4.7)。
和索引一樣,表中每個域的值也可以是任何類型。 需要特別指出的是:既然函數(shù)是一等公民,那么表的域也可以是函數(shù)。 這樣,表就可以攜帶 方法 了。 (參見 §3.4.11)。
索引一張表的原則遵循語言中的直接比較規(guī)則。
當(dāng)且僅當(dāng) i
與 j
直接比較相等時
(即不通過元方法的比較),
表達(dá)式 a[i]
與 a[j]
表示了表中相同的元素。
特別指出:一個可以完全表示為整數(shù)的浮點數(shù)和對應(yīng)的整數(shù)相等
(例如:1.0 == 1
)。
為了消除歧義,當(dāng)一個可以完全表示為整數(shù)的浮點數(shù)做為鍵值時,
都會被轉(zhuǎn)換為對應(yīng)的整數(shù)儲存。
例如,當(dāng)你寫 a[2.0] = true
時,
實際被插入表中的鍵是整數(shù) 2
。
(另一方面,2 與 "2
" 是兩個不同的 Lua 值,
故而它們可以是同一張表中的不同項。)
表、函數(shù)、線程、以及完全用戶數(shù)據(jù)在 Lua 中被稱為 對象: 變量并不真的 持有 它們的值,而僅保存了對這些對象的 引用。 賦值、參數(shù)傳遞、函數(shù)返回,都是針對引用而不是針對值的操作, 這些操作均不會做任何形式的隱式拷貝。
庫函數(shù) type
用于以字符串形式返回給定值的類型。
(參見 §6.1)。
后面在 §3.2 以及 §3.3.3 會討論,
引用一個叫 var
的自由名字(指在任何層級都未被聲明的名字)
在句法上都被翻譯為 _ENV.var
。
此外,每個被編譯的 Lua 代碼塊都會有一個外部的局部變量叫 _ENV
(參見 §3.3.2),
因此,_ENV
這個名字永遠(yuǎn)都不會成為一個代碼塊中的自由名字。
在轉(zhuǎn)譯那些自由名字時,_ENV
是否是那個外部的局部變量無所謂。
_ENV
和其它你可以使用的變量名沒有區(qū)別。
這里特別指出,你可以定義一個新變量或指定一個參數(shù)叫這個名字。
當(dāng)編譯器在轉(zhuǎn)譯自由名字時所用到的 _ENV
,
指的是你的程序在那個點上可見的那個名為 _ENV 的變量。
(Lua 的可見性規(guī)則參見 §3.5)
被 _ENV
用于值的那張表被稱為 環(huán)境。
Lua 保有一個被稱為 全局環(huán)境 特別環(huán)境。它被保存在 C 注冊表
(參見 §4.5)的一個特別索引下。
在 Lua 中,全局變量 _G
被初始化為這個值。
(_G
不被內(nèi)部任何地方使用。)
當(dāng) Lua 加載一個代碼塊,_ENV
這個上值的默認(rèn)值就是這個全局環(huán)境
(參見 load
)。
因此,在默認(rèn)情況下,Lua 代碼中提及的自由名字都指的全局環(huán)境中的相關(guān)項
(因此,它們也被稱為 全局變量 )。
此外,所有的標(biāo)準(zhǔn)庫都被加載入全局環(huán)境,一些函數(shù)也針對這個環(huán)境做操作。
你可以用 load
(或 loadfile
)加載代碼塊,并賦予它們不同的環(huán)境。
(在 C 里,當(dāng)你加載一個代碼塊后,可以通過改變它的第一個上值來改變它的環(huán)境。)
由于 Lua 是一門嵌入式擴(kuò)展語言,其所有行為均源于宿主程序中 C 代碼對某個 Lua 庫函數(shù)的調(diào)用。
(單獨使用 Lua 時,lua
程序就是宿主程序。)
所以,在編譯或運行 Lua 代碼塊的過程中,無論何時發(fā)生錯誤,
控制權(quán)都返回給宿主,由宿主負(fù)責(zé)采取恰當(dāng)?shù)拇胧ū热绱蛴″e誤消息)。
可以在 Lua 代碼中調(diào)用 error
函數(shù)來顯式地拋出一個錯誤。
如果你需要在 Lua 中捕獲這些錯誤,
可以使用 pcall
或
xpcall
在 保護(hù)模式 下調(diào)用一個函數(shù)。
無論何時出現(xiàn)錯誤,都會拋出一個攜帶錯誤信息的 錯誤對象 (錯誤消息)。 Lua 本身只會為錯誤生成字符串類型的錯誤對象, 但你的程序可以為錯誤生成任何類型的錯誤對象, 這就看你的 Lua 程序或宿主程序如何處理這些錯誤對象。
使用 xpcall
或
lua_pcall
時,
你應(yīng)該提供一個 消息處理函數(shù) 用于錯誤拋出時調(diào)用。
該函數(shù)需接收原始的錯誤消息,并返回一個新的錯誤消息。
它在錯誤發(fā)生后棧尚未展開時調(diào)用,
因此可以利用棧來收集更多的信息,
比如通過探知棧來創(chuàng)建一組?;厮菪畔ⅰ?同時,該處理函數(shù)也處于保護(hù)模式下,所以該函數(shù)內(nèi)發(fā)生的錯誤會再次觸發(fā)它(遞歸)。
如果遞歸太深,Lua 會終止調(diào)用并返回一個合適的消息。
Lua 中的每個值都可以有一個 元表。
這個 元表 就是一個普通的 Lua 表,
它用于定義原始值在特定操作下的行為。
如果你想改變一個值在特定操作下的行為,你可以在它的元表中設(shè)置對應(yīng)域。
例如,當(dāng)你對非數(shù)字值做加操作時,
Lua 會檢查該值的元表中的 "__add
" 域下的函數(shù)。
如果能找到,Lua 則調(diào)用這個函數(shù)來完成加這個操作。
在元表中事件的鍵值是一個雙下劃線(__
)加事件名的字符串;
鍵關(guān)聯(lián)的那些值被稱為 元方法。
在上一個例子中,__add
就是鍵值,
對應(yīng)的元方法是執(zhí)行加操作的函數(shù)。
你可以用 getmetatable
函數(shù)
來獲取任何值的元表。
Lua 使用直接訪問的方式從元表中查詢元方法(參見rawget
)。
所以,從對象 o
中獲取事件 ev
的元方法等價于下面的代碼:
rawget(getmetatable(o) or {}, "__ev")
你可以使用 setmetatable
來替換一張表的元表。在 Lua 中,你不可以改變表以外其它類型的值的元表
(除非你使用調(diào)試庫(參見§6.10));
若想改變這些非表類型的值的元表,請使用 C API。
表和完全用戶數(shù)據(jù)有獨立的元表 (當(dāng)然,多個表和用戶數(shù)據(jù)可以共享同一個元表)。 其它類型的值按類型共享元表; 也就是說所有的數(shù)字都共享同一個元表, 所有的字符串共享另一個元表等等。 默認(rèn)情況下,值是沒有元表的, 但字符串庫在初始化的時候為字符串類型設(shè)置了元表 (參見 §6.4)。
元表決定了一個對象在數(shù)學(xué)運算、位運算、比較、連接、 取長度、調(diào)用、索引時的行為。 元表還可以定義一個函數(shù),當(dāng)表對象或用戶數(shù)據(jù)對象在垃圾回收 (參見§2.5)時調(diào)用它。
對于一元操作符(取負(fù)、求長度、位反), 元方法調(diào)用的時候,第二個參數(shù)是個啞元,其值等于第一個參數(shù)。 這樣處理僅僅是為了簡化 Lua 的內(nèi)部實現(xiàn) (這樣處理可以讓所有的操作都和二元操作一致), 這個行為有可能在將來的版本中移除。 (使用這個額外參數(shù)的行為都是不確定的。)
接下來是元表可以控制的事件的詳細(xì)列表。
每個操作都用對應(yīng)的事件名來區(qū)分。
每個事件的鍵名用加有 '__
' 前綴的字符串來表示;
例如 "add" 操作的鍵名為字符串 "__add
"。
__add
:
+
操作。
如果任何不是數(shù)字的值(包括不能轉(zhuǎn)換為數(shù)字的字符串)做加法,
Lua 就會嘗試調(diào)用元方法。
首先、Lua 檢查第一個操作數(shù)(即使它是合法的),
如果這個操作數(shù)沒有為 "__add
" 事件定義元方法,
Lua 就會接著檢查第二個操作數(shù)。
一旦 Lua 找到了元方法,
它將把兩個操作數(shù)作為參數(shù)傳入元方法,
元方法的結(jié)果(調(diào)整為單個值)作為這個操作的結(jié)果。
如果找不到元方法,將拋出一個錯誤。
__sub
:
-
操作。
行為和 "add" 操作類似。
__mul
:
*
操作。
行為和 "add" 操作類似。
__div
:
/
操作。
行為和 "add" 操作類似。
__mod
:
%
操作。
行為和 "add" 操作類似。
__pow
:
^
(次方)操作。
行為和 "add" 操作類似。
__unm
:
-
(取負(fù))操作。
行為和 "add" 操作類似。
__idiv
:
//
(向下取整除法)操作。
行為和 "add" 操作類似。
__band
:
&
(按位與)操作。
行為和 "add" 操作類似,
不同的是 Lua 會在任何一個操作數(shù)無法轉(zhuǎn)換為整數(shù)時
(參見 §3.4.3)嘗試取元方法。
__bor
:
|
(按位或)操作。
行為和 "band" 操作類似。
__bxor
:
~
(按位異或)操作。
行為和 "band" 操作類似。
__bnot
:
~
(按位非)操作。
行為和 "band" 操作類似。
__shl
:
<<
(左移)操作。
行為和 "band" 操作類似。
__shr
:
>>
(右移)操作。
行為和 "band" 操作類似。
__concat
:
..
(連接)操作。
行為和 "add" 操作類似,
不同的是 Lua 在任何操作數(shù)即不是一個字符串
也不是數(shù)字(數(shù)字總能轉(zhuǎn)換為對應(yīng)的字符串)的情況下嘗試元方法。
__len
:
#
(取長度)操作。
如果對象不是字符串,Lua 會嘗試它的元方法。
如果有元方法,則調(diào)用它并將對象以參數(shù)形式傳入,
而返回值(被調(diào)整為單個)則作為結(jié)果。
如果對象是一張表且沒有元方法,
Lua 使用表的取長度操作(參見 §3.4.7)。
其它情況,均拋出錯誤。
__eq
:
==
(等于)操作。
和 "add" 操作行為類似,
不同的是 Lua 僅在兩個值都是表或都是完全用戶數(shù)據(jù)
且它們不是同一個對象時才嘗試元方法。
調(diào)用的結(jié)果總會被轉(zhuǎn)換為布爾量。
__lt
:
<
(小于)操作。
和 "add" 操作行為類似,
不同的是 Lua 僅在兩個值不全為整數(shù)也不全為字符串時才嘗試元方法。
調(diào)用的結(jié)果總會被轉(zhuǎn)換為布爾量。
__le
:
<=
(小于等于)操作。
和其它操作不同,
小于等于操作可能用到兩個不同的事件。
首先,像 "lt" 操作的行為那樣,Lua 在兩個操作數(shù)中查找 "__le
" 元方法。
如果一個元方法都找不到,就會再次查找 "__lt
" 事件,
它會假設(shè) a <= b
等價于 not (b < a)
。
而其它比較操作符類似,其結(jié)果會被轉(zhuǎn)換為布爾量。
__index
:
索引 table[key]
。
當(dāng) table
不是表或是表 table
中不存在
key
這個鍵時,這個事件被觸發(fā)。
此時,會讀出 table
相應(yīng)的元方法。
盡管名字取成這樣,
這個事件的元方法其實可以是一個函數(shù)也可以是一張表。
如果它是一個函數(shù),則以 table
和 key
作為參數(shù)調(diào)用它。
如果它是一張表,最終的結(jié)果就是以 key
取索引這張表的結(jié)果。
(這個索引過程是走常規(guī)的流程,而不是直接索引,
所以這次索引有可能引發(fā)另一次元方法。)
__newindex
:
索引賦值 table[key] = value
。
和索引事件類似,它發(fā)生在
table
不是表或是表 table
中不存在
key
這個鍵的時候。
此時,會讀出 table
相應(yīng)的元方法。
同索引過程那樣,
這個事件的元方法即可以是函數(shù),也可以是一張表。
如果是一個函數(shù),
則以 table
、 key
、以及 value
為參數(shù)傳入。
如果是一張表,
Lua 對這張表做索引賦值操作。
(這個索引過程是走常規(guī)的流程,而不是直接索引賦值,
所以這次索引賦值有可能引發(fā)另一次元方法。)
一旦有了 "newindex" 元方法,
Lua 就不再做最初的賦值操作。
(如果有必要,在元方法內(nèi)部可以調(diào)用 rawset
來做賦值。)
__call
:
函數(shù)調(diào)用操作 func(args)
。
當(dāng) Lua 嘗試調(diào)用一個非函數(shù)的值的時候會觸發(fā)這個事件
(即 func
不是一個函數(shù))。
查找 func
的元方法,
如果找得到,就調(diào)用這個元方法,
func
作為第一個參數(shù)傳入,原來調(diào)用的參數(shù)(args
)后依次排在后面。
Lua 采用了自動內(nèi)存管理。 這意味著你不用操心新創(chuàng)建的對象需要的內(nèi)存如何分配出來, 也不用考慮在對象不再被使用后怎樣釋放它們所占用的內(nèi)存。 Lua 運行了一個 垃圾收集器 來收集所有 死對象 (即在 Lua 中不可能再訪問到的對象)來完成自動內(nèi)存管理的工作。 Lua 中所有用到的內(nèi)存,如:字符串、表、用戶數(shù)據(jù)、函數(shù)、線程、 內(nèi)部結(jié)構(gòu)等,都服從自動管理。
Lua 實現(xiàn)了一個增量標(biāo)記-掃描收集器。 它使用這兩個數(shù)字來控制垃圾收集循環(huán): 垃圾收集器間歇率 和 垃圾收集器步進(jìn)倍率。 這兩個數(shù)字都使用百分?jǐn)?shù)為單位 (例如:值 100 在內(nèi)部表示 1 )。
垃圾收集器間歇率控制著收集器需要在開啟新的循環(huán)前要等待多久。 增大這個值會減少收集器的積極性。 當(dāng)這個值比 100 小的時候,收集器在開啟新的循環(huán)前不會有等待。 設(shè)置這個值為 200 就會讓收集器等到總內(nèi)存使用量達(dá)到 之前的兩倍時才開始新的循環(huán)。
垃圾收集器步進(jìn)倍率控制著收集器運作速度相對于內(nèi)存分配速度的倍率。 增大這個值不僅會讓收集器更加積極,還會增加每個增量步驟的長度。 不要把這個值設(shè)得小于 100 , 那樣的話收集器就工作的太慢了以至于永遠(yuǎn)都干不完一個循環(huán)。 默認(rèn)值是 200 ,這表示收集器以內(nèi)存分配的“兩倍”速工作。
如果你把步進(jìn)倍率設(shè)為一個非常大的數(shù)字 (比你的程序可能用到的字節(jié)數(shù)還大 10% ), 收集器的行為就像一個 stop-the-world 收集器。 接著你若把間歇率設(shè)為 200 , 收集器的行為就和過去的 Lua 版本一樣了: 每次 Lua 使用的內(nèi)存翻倍時,就做一次完整的收集。
你可以通過在 C 中調(diào)用 lua_gc
或在 Lua 中調(diào)用 collectgarbage
來改變這倆數(shù)字。
這兩個函數(shù)也可以用來直接控制收集器(例如停止它或重啟它)。
你可以為表設(shè)定垃圾收集的元方法, 對于完全用戶數(shù)據(jù)(參見 §2.4), 則需要使用 C API 。 該元方法被稱為 終結(jié)器。 終結(jié)器允許你配合 Lua 的垃圾收集器做一些額外的資源管理工作 (例如關(guān)閉文件、網(wǎng)絡(luò)或數(shù)據(jù)庫連接,或是釋放一些你自己的內(nèi)存)。
如果要讓一個對象(表或用戶數(shù)據(jù))在收集過程中進(jìn)入終結(jié)流程,
你必須 標(biāo)記 它需要觸發(fā)終結(jié)器。
當(dāng)你為一個對象設(shè)置元表時,若此刻這張元表中用一個以字符串
"__gc
" 為索引的域,那么就標(biāo)記了這個對象需要觸發(fā)終結(jié)器。
注意:如果你給對象設(shè)置了一個沒有 __gc
域的元表,之后才給元表加上這個域,
那么這個對象是沒有被標(biāo)記成需要觸發(fā)終結(jié)器的。
然而,一旦對象被標(biāo)記,
你還是可以自由的改變其元表中的 __gc
域的。
當(dāng)一個被標(biāo)記的對象成為了垃圾后,
垃圾收集器并不會立刻回收它。
取而代之的是,Lua 會將其置入一個鏈表。
在收集完成后,Lua 將遍歷這個鏈表。
Lua 會檢查每個鏈表中的對象的 __gc
元方法:如果是一個函數(shù),那么就以對象為唯一參數(shù)調(diào)用它;
否則直接忽略它。
在每次垃圾收集循環(huán)的最后階段, 本次循環(huán)中檢測到的需要被回收之對象, 其終結(jié)器的觸發(fā)次序按當(dāng)初給對象作需要觸發(fā)終結(jié)器的標(biāo)記之次序的逆序進(jìn)行; 這就是說,第一個被調(diào)用的終結(jié)器是程序中最后一個被標(biāo)記的對象所攜的那個。 每個終結(jié)器的運行可能發(fā)生在執(zhí)行常規(guī)代碼過程中的任意一刻。
由于被回收的對象還需要被終結(jié)器使用, 該對象(以及僅能通過它訪問到的其它對象)一定會被 Lua 復(fù)活。 通常,復(fù)活是短暫的,對象所屬內(nèi)存會在下一個垃圾收集循環(huán)釋放。 然后,若終結(jié)器又將對象保存去一些全局的地方 (例如:放在一個全局變量里),這次復(fù)活就持續(xù)生效了。 此外,如果在終結(jié)器中對一個正進(jìn)入終結(jié)流程的對象再次做一次標(biāo)記讓它觸發(fā)終結(jié)器, 只要這個對象在下個循環(huán)中依舊不可達(dá),它的終結(jié)函數(shù)還會再調(diào)用一次。 無論是哪種情況, 對象所屬內(nèi)存僅在垃圾收集循環(huán)中該對象不可達(dá)且 沒有被標(biāo)記成需要觸發(fā)終結(jié)器才會被釋放。
當(dāng)你關(guān)閉一個狀態(tài)機(參見 lua_close
),
Lua 將調(diào)用所有被標(biāo)記了需要觸發(fā)終結(jié)器對象的終結(jié)過程,
其次序為標(biāo)記次序的逆序。
在這個過程中,任何終結(jié)器再次標(biāo)記對象的行為都不會生效。
弱表 指內(nèi)部元素為 弱引用 的表。 垃圾收集器會忽略掉弱引用。 換句話說,如果一個對象只被弱引用引用到, 垃圾收集器就會回收這個對象。
一張弱表可以有弱鍵或是弱值,也可以鍵值都是弱引用。
含有弱值的表允許收集器回收它的值,但會阻止收集器回收它的鍵。
若一張表的鍵值均為弱引用,
那么收集器可以回收其中的任意鍵和值。
任何情況下,只要鍵或值的任意一項被回收,
相關(guān)聯(lián)的鍵值對都會從表中移除。
一張表的元表中的 __mode
域控制著這張表的弱屬性。
當(dāng) __mode
域是一個包含字符 'k
'
的字符串時,這張表的所有鍵皆為弱引用。
當(dāng) __mode
域是一個包含字符 'v
'
的字符串時,這張表的所有值皆為弱引用。
屬性為弱鍵強值的表也被稱為 暫時表。 對于一張暫時表, 它的值是否可達(dá)僅取決于其對應(yīng)鍵是否可達(dá)。 特別注意,如果表內(nèi)的一個鍵僅僅被其值所關(guān)聯(lián)引用, 這個鍵值對將被表內(nèi)移除。
對一張表的弱屬性的修改僅在下次收集循環(huán)才生效。 尤其是當(dāng)你把表由弱改強,Lua 還是有可能在修改生效前回收表內(nèi)一些項目。
只有那些有顯式構(gòu)造過程的對象才會從弱表中移除。 值,例如數(shù)字和輕量 C 函數(shù),不受垃圾收集器管轄, 因此不會從弱表中移除 (除非它們的關(guān)聯(lián)項被回收)。 雖然字符串受垃圾回收器管轄, 但它們沒有顯式的構(gòu)造過程,所以也不會從弱表中移除。
弱表針對復(fù)活的對象 (指那些正在走終結(jié)流程,僅能被終結(jié)器訪問的對象) 有著特殊的行為。 弱值引用的對象,在運行它們的終結(jié)器前就被移除了, 而弱鍵引用的對象則要等到終結(jié)器運行完畢后,到下次收集當(dāng)對象真的被釋放時才被移除。 這個行為使得終結(jié)器運行時得以訪問到由該對象在弱表中所關(guān)聯(lián)的屬性。
如果一張弱表在當(dāng)次收集循環(huán)內(nèi)的復(fù)活對象中, 那么在下個循環(huán)前這張表有可能未被正確地清理。
Lua 支持協(xié)程,也叫 協(xié)同式多線程。 一個協(xié)程在 Lua 中代表了一段獨立的執(zhí)行線程。 然而,與多線程系統(tǒng)中的線程的區(qū)別在于, 協(xié)程僅在顯式調(diào)用一個讓出(yield)函數(shù)時才掛起當(dāng)前的執(zhí)行。
調(diào)用函數(shù)
coroutine.create
可創(chuàng)建一個協(xié)程。
其唯一的參數(shù)是該協(xié)程的主函數(shù)。
create
函數(shù)只負(fù)責(zé)新建一個協(xié)程并返回其句柄
(一個 thread 類型的對象);
而不會啟動該協(xié)程。
調(diào)用
coroutine.resume
函數(shù)執(zhí)行一個協(xié)程。
第一次調(diào)用
coroutine.resume
時,第一個參數(shù)應(yīng)傳入
coroutine.create
返回的線程對象,然后協(xié)程從其主函數(shù)的第一行開始執(zhí)行。
傳遞給
coroutine.resume
的其他參數(shù)將作為協(xié)程主函數(shù)的參數(shù)傳入。
協(xié)程啟動之后,將一直運行到它終止或 讓出。
協(xié)程的運行可能被兩種方式終止:
正常途徑是主函數(shù)返回
(顯式返回或運行完最后一條指令);
非正常途徑是發(fā)生了一個未被捕獲的錯誤。
對于正常結(jié)束,
coroutine.resume
將返回 true,
并接上協(xié)程主函數(shù)的返回值。
當(dāng)錯誤發(fā)生時,
coroutine.resume
將返回 false
與錯誤消息。
通過調(diào)用
coroutine.yield
使協(xié)程暫停執(zhí)行,讓出執(zhí)行權(quán)。
協(xié)程讓出時,對應(yīng)的最近 coroutine.resume
函數(shù)會立刻返回,即使該讓出操作發(fā)生在內(nèi)嵌函數(shù)調(diào)用中
(即不在主函數(shù),但在主函數(shù)直接或間接調(diào)用的函數(shù)內(nèi)部)。
在協(xié)程讓出的情況下,
coroutine.resume
也會返回 true,
并加上傳給
coroutine.yield
的參數(shù)。
當(dāng)下次重啟同一個協(xié)程時,
協(xié)程會接著從讓出點繼續(xù)執(zhí)行。
此時,此前讓出點處對 coroutine.yield
的調(diào)用
會返回,返回值為傳給
coroutine.resume
的第一個參數(shù)之外的其他參數(shù)。
與
coroutine.create
類似,
coroutine.wrap
函數(shù)也會創(chuàng)建一個協(xié)程。
不同之處在于,它不返回協(xié)程本身,而是返回一個函數(shù)。
調(diào)用這個函數(shù)將啟動該協(xié)程。
傳遞給該函數(shù)的任何參數(shù)均當(dāng)作 coroutine.resume
的額外參數(shù)。
coroutine.wrap
返回
coroutine.resume
的所有返回值,除了第一個返回值(布爾型的錯誤碼)。
和 coroutine.resume
不同,
coroutine.wrap
不會捕獲錯誤;
而是將任何錯誤都傳播給調(diào)用者。
下面的代碼展示了一個協(xié)程工作的范例:
function foo (a) print("foo", a) return coroutine.yield(2*a) end co = coroutine.create(function (a,b) print("co-body", a, b) local r = foo(a+1) print("co-body", r) local r, s = coroutine.yield(a+b, a-b) print("co-body", r, s) return b, "end" end) print("main", coroutine.resume(co, 1, 10)) print("main", coroutine.resume(co, "r")) print("main", coroutine.resume(co, "x", "y")) print("main", coroutine.resume(co, "x", "y"))
當(dāng)你運行它,將產(chǎn)生下列輸出:
co-body 1 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 來創(chuàng)建及操作協(xié)程:
參見函數(shù)
lua_newthread
,
lua_resume
,
以及 lua_yield
。
這一章描述了 Lua 的詞法、語法和句法。 換句話說,本章描述哪些符記是有效的, 它們?nèi)绾伪唤M合起來,這些組合方式有什么含義。
關(guān)于語言的構(gòu)成概念將用常見的擴(kuò)展 BNF 表達(dá)式寫出。 也就是這個樣子: {a} 表示 0 或多個 a, [a] 表示一個可選的 a。 可以被分解的非最終符號會這樣寫 non-terminal , 關(guān)鍵字會寫成這樣 kword, 而其它不能被分解的最終符號則寫成這樣 ‘=’ 。 完整的 Lua 語法可以在本手冊最后一章 §9 找到。
Lua 語言的格式自由。 它會忽略語法元素(符記)間的空格(包括換行)和注釋, 僅把它們看作為名字和關(guān)鍵字間的分割符。
Lua 中的 名字 (也被稱為 標(biāo)識符) 可以是由非數(shù)字打頭的任意字母下劃線和數(shù)字構(gòu)成的字符串。 標(biāo)識符可用于對變量、表的域、以及標(biāo)簽命名。
下列 關(guān)鍵字 是保留的,不可用于名字:
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
則是兩個不同的有效名字。
作為一個約定,程序應(yīng)避免創(chuàng)建以下劃線加一個或多個大寫字母構(gòu)成的名字
(例如 _VERSION
)。
下列字符串是另外一些符記:
+ - * / % ^ # & ~ | << >> // == ~= <= >= < > = ( ) { } [ ] :: ; : , . .. ...
字面串 可以用單引號或雙引號括起。
字面串內(nèi)部可以包含下列 C 風(fēng)格的轉(zhuǎn)義串:
'\a
' (響鈴),
'\b
' (退格),
'\f
' (換頁),
'\n
' (換行),
'\r
' (回車),
'\t
' (橫項制表),
'\v
' (縱向制表),
'\\
' (反斜杠),
'\"
' (雙引號),
以及 '\'
' (單引號)。
在反斜杠后跟一個真正的換行等價于在字符串中寫一個換行符。
轉(zhuǎn)義串 '\z
' 會忽略其后的一系列空白符,包括換行;
它在你需要對一個很長的字符串常量斷行為多行并希望在每個新行保持縮進(jìn)時非常有用。
Lua 中的字符串可以保存任意 8 位值,其中包括用 '\0
' 表示的 0 。
一般而言,你可以用字符的數(shù)字值來表示這個字符。
方式是用轉(zhuǎn)義串 \xXX
,
此處的 XX 必須是恰好兩個字符的 16 進(jìn)制數(shù)。
或者你也可以使用轉(zhuǎn)義串 \ddd
,
這里的 ddd 是一到三個十進(jìn)制數(shù)字。
(注意,如果在轉(zhuǎn)義符后接著恰巧是一個數(shù)字符號的話,
你就必須在這個轉(zhuǎn)義形式中寫滿三個數(shù)字。)
對于用 UTF-8 編碼的 Unicode 字符,你可以用
轉(zhuǎn)義符 \u{XXX}
來表示
(這里必須有一對花括號),
此處的 XXX 是用 16 進(jìn)制表示的字符編號。
字面串還可以用一種 長括號 括起來的方式定義。
我們把兩個正的方括號間插入 n 個等號定義為 第 n 級開長括號。
就是說,0 級開的長括號寫作 [[
, 一級開長括號寫作 [=[
,
如此等等。
閉長括號也作類似定義;
舉個例子,4 級反的長括號寫作 ]====]
。
一個 長字面串 可以由任何一級的開長括號開始,而由第一個碰到的同級的閉長括號結(jié)束。
這種方式描述的字符串可以包含任何東西,當(dāng)然特定級別的反長括號除外。
整個詞法分析過程將不受分行限制,不處理任何轉(zhuǎn)義符,并且忽略掉任何不同級別的長括號。
其中碰到的任何形式的換行串(回車、換行、回車加換行、換行加回車),都會被轉(zhuǎn)換為單個換行符。
字面串中的每個不被上述規(guī)則影響的字節(jié)都呈現(xiàn)為本身。 然而,Lua 是用文本模式打開源文件解析的, 一些系統(tǒng)的文件操作函數(shù)對某些控制字符的處理可能有問題。 因此,對于非文本數(shù)據(jù),用引號括起來并顯式按轉(zhuǎn)義符規(guī)則來表述更安全。
為了方便起見,
當(dāng)一個開長括號后緊接一個換行符時,
這個換行符不會放在字符串內(nèi)。
舉個例子,假設(shè)一個系統(tǒng)使用 ASCII 碼
(此時 'a
' 編碼為 97 ,
換行編碼為 10 ,'1
' 編碼為 49 ),
下面五種方式描述了完全相同的字符串:
a = 'alo\n123"' a = "alo\n123\"" a = '\97lo\10\04923"' a = [[alo 123"]] a = [==[ alo 123"]==]
數(shù)字常量 (或稱為 數(shù)字量)
可以由可選的小數(shù)部分和可選的十為底的指數(shù)部分構(gòu)成,
指數(shù)部分用字符 'e
' 或 'E
' 來標(biāo)記。
Lua 也接受以 0x
或 0X
開頭的 16 進(jìn)制常量。
16 進(jìn)制常量也接受小數(shù)加指數(shù)部分的形式,指數(shù)部分是以二為底,
用字符 'p
' 或 'P
' 來標(biāo)記。
數(shù)字常量中包含小數(shù)點或指數(shù)部分時,被認(rèn)為是一個浮點數(shù);
否則被認(rèn)為是一個整數(shù)。
下面有一些合法的整數(shù)常量的例子:
3 345 0xff 0xBEBADA
以下為合法的浮點常量:
3.0 3.1416 314.16e-2 0.31416E1 34e1 0x0.1E 0xA23p-4 0X1.921FB54442D18P+1
在字符串外的任何地方出現(xiàn)以雙橫線 (--
) 開頭的部分是 注釋 。
如果 --
后沒有緊跟著一個開大括號,
該注釋為 短注釋,
注釋到當(dāng)前行末截至。
否則,這是一段 長注釋 ,
注釋區(qū)一直維持到對應(yīng)的閉長括號。
長注釋通常用于臨時屏蔽掉一大段代碼。
變量是儲存值的地方。 Lua 中有三種變量: 全局變量、局部變量和表的域。
單個名字可以指代一個全局變量也可以指代一個局部變量 (或者是一個函數(shù)的形參,這是一種特殊形式的局部變量)。
var ::= Name
名字指 §3.1 中定義的標(biāo)識符。
所有沒有顯式聲明為局部變量(參見 §3.3.7) 的變量名都被當(dāng)做全局變量。 局部變量有其 作用范圍 : 局部變量可以被定義在它作用范圍中的函數(shù)自由使用(參見 §3.5)。
在變量的首次賦值之前,變量的值均為 nil。
方括號被用來對表作索引:
var ::= prefixexp ‘[’ exp ‘]’
對全局變量以及表的域之訪問的含義可以通過元表來改變。
以索引方式訪問一個變量 t[i]
等價于
調(diào)用 gettable_event(t,i)
。
(參見 §2.4 ,有一份完整的關(guān)于
gettable_event
函數(shù)的說明。
這個函數(shù)并沒有在 lua 中定義出來,也不能在 lua 中調(diào)用。這里我們把提到它只是方便說明問題。)
var.Name
這種語法只是一個語法糖,用來表示
var["Name"]
:
var ::= prefixexp ‘.’ Name
對全局變量 x
的操作等價于操作
_ENV.x
。
由于代碼塊編譯的方式,
_ENV
永遠(yuǎn)也不可能是一個全局名字 (參見 §2.2)。
Lua 支持所有與 Pascal 或是 C 類似的常見形式的語句, 這個集合包括賦值,控制結(jié)構(gòu),函數(shù)調(diào)用,還有變量聲明。
語句塊是一個語句序列,它們會按次序執(zhí)行:
block ::= {stat}
Lua 支持 空語句, 你可以用分號分割語句,也可以以分號開始一個語句塊, 或是連著寫兩個分號:
stat ::= ‘;’
函數(shù)調(diào)用和賦值語句都可能以一個小括號打頭, 這可能讓 Lua 的語法產(chǎn)生歧義。 我們來看看下面的代碼片斷:
a = b + c (print or io.write)('done')
從語法上說,可能有兩種解釋方式:
a = b + c(print or io.write)('done') a = b + c; (print or io.write)('done')
當(dāng)前的解析器總是用第一種結(jié)構(gòu)來解析, 它會將開括號看成函數(shù)調(diào)用的參數(shù)傳遞開始處。 為了避免這種二義性, 在一條語句以小括號開頭時,前面放一個分號是個好習(xí)慣:
;(print or io.write)('done')
一個語句塊可以被顯式的定界為單條語句:
stat ::= do block end
顯式的對一個塊定界通常用來控制內(nèi)部變量聲明的作用域。 有時,顯式定界也用于在一個語句塊中間插入 return (參見 §3.3.4)。
Lua 的一個編譯單元被稱為一個 代碼塊。 從句法構(gòu)成上講,一個代碼塊就是一個語句塊。
chunk ::= block
Lua 把一個代碼塊當(dāng)作一個擁有不定參數(shù)的匿名函數(shù)
(參見§3.4.11)來處理。
正是這樣,代碼塊內(nèi)可以定義局部變量,它可以接收參數(shù),返回若干值。
此外,這個匿名函數(shù)在編譯時還為它的作用域綁定了一個外部局部變量
_ENV
(參見 §2.2)。
該函數(shù)總是把 _ENV
作為它唯一的一個上值,
即使這個函數(shù)不使用這個變量,它也存在。
代碼塊可以被保存在文件中,也可以作為宿主程序內(nèi)部的一個字符串。 要執(zhí)行一個代碼塊, 首先要讓 Lua 加載 它, 將代碼塊中的代碼預(yù)編譯成虛擬機中的指令, 而后,Lua 用虛擬機解釋器來運行編譯后的代碼。
代碼塊可以被預(yù)編譯為二進(jìn)制形式;
參見程序 luac
以及函數(shù) string.dump
可獲得更多細(xì)節(jié)。
用源碼表示的程序和編譯后的形式可自由替換;
Lua 會自動檢測文件格式做相應(yīng)的處理
(參見 load
)。
Lua 允許多重賦值。 因此,賦值的語法定義是等號左邊放一個變量列表, 而等號右邊放一個表達(dá)式列表。 兩邊的列表中的元素都用逗號間開:
stat ::= varlist ‘=’ explist varlist ::= var {‘,’ var} explist ::= exp {‘,’ exp}
表達(dá)式放在 §3.4 中討論。
在作賦值操作之前, 那值列表會被 調(diào)整 為左邊變量列表的個數(shù)。 如果值比需要的更多的話,多余的值就被扔掉。 如果值的數(shù)量不夠需求, 將會按所需擴(kuò)展若干個 nil。 如果表達(dá)式列表以一個函數(shù)調(diào)用結(jié)束, 這個函數(shù)所返回的所有值都會在調(diào)整操作之前被置入值列表中 (除非這個函數(shù)調(diào)用被用括號括了起來;參見 §3.4)。
賦值語句首先讓所有的表達(dá)式完成運算, 之后再做賦值操作。 因此,下面這段代碼
i = 3 i, a[i] = i+1, 20
會把 a[3]
設(shè)置為 20,而不會影響到 a[4]
。
這是因為 a[i]
中的 i
在被賦值為 4 之前就被計算出來了(當(dāng)時是 3 )。
簡單說 ,這樣一行
x, y = y, x
會交換 x
和 y
的值,
及
x, y, z = y, z, x
會輪換 x
,y
,z
的值。
對全局變量以及表的域的賦值操作的含義可以通過元表來改變。
對 t[i] = val
這樣的變量索引賦值,
等價于 settable_event(t,i,val)
。
(關(guān)于函數(shù) settable_event
的詳細(xì)說明,參見
§2.4。
這個函數(shù)并沒有在 Lua 中定義出來,也不可以被調(diào)用。
這里我們列出來,僅僅出于方便解釋的目的。)
對于全局變量 x = val
的賦值等價于
_ENV.x = val
(參見 §2.2)。
if, while, and repeat 這些控制結(jié)構(gòu)符合通常的意義,而且也有類似的語法:
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)。
控制結(jié)構(gòu)中的條件表達(dá)式可以返回任何值。 false 與 nil 兩者都被認(rèn)為是假。 所有不同于 nil 與 false 的其它值都被認(rèn)為是真 (特別需要注意的是,數(shù)字 0 和空字符串也被認(rèn)為是真)。
在 repeat–until 循環(huán)中, 內(nèi)部語句塊的結(jié)束點不是在 until 這個關(guān)鍵字處, 它還包括了其后的條件表達(dá)式。 因此,條件表達(dá)式中可以使用循環(huán)內(nèi)部語句塊中的定義的局部變量。
goto 語句將程序的控制點轉(zhuǎn)移到一個標(biāo)簽處。 由于句法上的原因, Lua 里的標(biāo)簽也被認(rèn)為是語句:
stat ::= goto Name stat ::= label label ::= ‘::’ Name ‘::’
除了在內(nèi)嵌函數(shù)中,以及在內(nèi)嵌語句塊中定義了同名標(biāo)簽,的情況外, 標(biāo)簽對于它定義所在的整個語句塊可見。 只要 goto 沒有進(jìn)入一個新的局部變量的作用域,它可以跳轉(zhuǎn)到任意可見標(biāo)簽處。
標(biāo)簽和沒有內(nèi)容的語句被稱為空語句,它們不做任何操作。
break 被用來結(jié)束 while、 repeat、或 for 循環(huán), 它將跳到循環(huán)外接著之后的語句運行:
stat ::= break
break 跳出最內(nèi)層的循環(huán)。
return 被用于從函數(shù)或是代碼塊(其實它就是一個函數(shù)) 中返回值。 函數(shù)可以返回不止一個值,所以 return 的語法為
stat ::= return [explist] [‘;’]
return 只能被寫在一個語句塊的最后一句。
如果你真的需要從語句塊的中間 return,
你可以使用顯式的定義一個內(nèi)部語句塊,
一般寫作 do return end
。
可以這樣寫是因為現(xiàn)在 return 成了(內(nèi)部)語句塊的最后一句了。
for 有兩種形式:一種是數(shù)字形式,另一種是通用形式。
數(shù)字形式的 for 循環(huán),通過一個數(shù)學(xué)運算不斷地運行內(nèi)部的代碼塊。 下面是它的語法:
stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end
block 將把 name 作循環(huán)變量。 從第一個 exp 開始起,直到第二個 exp 的值為止, 其步長為第三個 exp 。 更確切的說,一個 for 循環(huán)看起來是這個樣子
for v = e1, e2, e3 do block end
這等價于代碼:
do local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3) if not (var and limit and step) then error() end var = var - step while true do var = var + step if (step >= 0 and var > limit) or (step < 0 and var < limit) then break end local v = var block end end
注意下面這幾點:
var
,limit
,以及 step
都是一些不可見的變量。
這里給它們起的名字都僅僅用于解釋方便。
v
是一個循環(huán)內(nèi)部的局部變量;
如果你需要在循環(huán)結(jié)束后使用這個值,
在退出循環(huán)前把它賦給另一個變量。
通用形式的 for 通過一個叫作 迭代器 的函數(shù)工作。 每次迭代,迭代器函數(shù)都會被調(diào)用以產(chǎn)生一個新的值, 當(dāng)這個值為 nil 時,循環(huán)停止。 通用形式的 for 循環(huán)的語法如下:
stat ::= for namelist in explist do block end namelist ::= Name {‘,’ Name}
這樣的 for 語句
for var_1, ···, var_n in explist do block end
它等價于這樣一段代碼:
do local f, s, var = explist while true do local var_1, ···, var_n = f(s, var) if var_1 == nil then break end var = var_1 block end end
注意以下幾點:
explist
只會被計算一次。
它返回三個值, 一個 迭代器 函數(shù),
一個 狀態(tài),
一個 迭代器的初始值。
f
, s
,與 var
都是不可見的變量。
這里給它們起的名字都只是為了解說方便。
var_i
對于循環(huán)來說是一個局部變量;
你不可以在 for 循環(huán)結(jié)束后繼續(xù)使用。
如果你需要保留這些值,那么就在循環(huán)跳出或結(jié)束前賦值到別的變量里去。
為了允許使用函數(shù)的副作用, 函數(shù)調(diào)用可以被作為一個語句執(zhí)行:
stat ::= functioncall
在這種情況下,所有的返回值都被舍棄。 函數(shù)調(diào)用在 §3.4.10 中解釋。
局部變量可以在語句塊中任何地方聲明。 聲明可以包含一個初始化賦值操作:
stat ::= local namelist [‘=’ explist]
如果有初始化值的話,初始化賦值操作的語法和賦值操作一致 (參見 §3.3.3 )。 若沒有初始化值,所有的變量都被初始化為 nil。
一個代碼塊同時也是一個語句塊(參見 §3.3.2), 所以局部變量可以放在代碼塊中那些顯式注明的語句塊之外。
局部變量的可見性規(guī)則在 §3.5 中解釋。
Lua 中有這些基本表達(dá)式:
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 ‘)’
數(shù)字和字面串在 §3.1 中解釋;
變量在 §3.2 中解釋;
函數(shù)定義在 §3.4.11 中解釋;
函數(shù)調(diào)用在 §3.4.10 中解釋;
表的構(gòu)造在 §3.4.9 中解釋。
可變參數(shù)的表達(dá)式寫作三個點('...
'),
它只能在有可變參數(shù)的函數(shù)中直接使用;這些在 §3.4.11 中解釋。
二元操作符包含有數(shù)學(xué)運算操作符(參見 §3.4.1), 位操作符(參見 §3.4.2), 比較操作符(參見 §3.4.4), 邏輯操作符(參見 §3.4.5), 以及連接操作符(參見 §3.4.6)。 一元操作符包括負(fù)號(參見 §3.4.1), 按位非(參見 §3.4.2), 邏輯非(參見 §3.4.5), 和取長度操作符(參見 §3.4.7)。
函數(shù)調(diào)用和可變參數(shù)表達(dá)式都可以放在多重返回值中。 如果函數(shù)調(diào)用被當(dāng)作一條語句(參見 §3.3.6), 其返回值列表被調(diào)整為零個元素,即拋棄所有的返回值。 如果表達(dá)式被用于表達(dá)式列表的最后(或是唯一的)一個元素, 那么不會做任何調(diào)整(除非表達(dá)式被括號括起來)。 在其它情況下, Lua 都會把結(jié)果調(diào)整為一個元素置入表達(dá)式列表中, 即保留第一個結(jié)果而忽略之后的所有值,或是在沒有結(jié)果時, 補單個 nil。
這里有一些例子:
f() -- 調(diào)整為 0 個結(jié)果 g(f(), x) -- f() 會被調(diào)整為一個結(jié)果 g(x, f()) -- g 收到 x 以及 f() 返回的所有結(jié)果 a,b,c = f(), x -- f() 被調(diào)整為 1 個結(jié)果 (c 收到 nil) a,b = ... -- a 收到可變參數(shù)列表的第一個參數(shù), -- b 收到第二個參數(shù)(如果可變參數(shù)列表中 -- 沒有實際的參數(shù),a 和 b 都會收到 nil) a,b,c = x, f() -- f() 被調(diào)整為 2 個結(jié)果 a,b,c = f() -- f() 被調(diào)整為 3 個結(jié)果 return f() -- 返回 f() 的所有返回結(jié)果 return ... -- 返回從可變參數(shù)列表中接收到的所有參數(shù)parameters return x,y,f() -- 返回 x, y, 以及 f() 的所有返回值 {f()} -- 用 f() 的所有返回值創(chuàng)建一個列表 {...} -- 用可變參數(shù)中的所有值創(chuàng)建一個列表 {f(), nil} -- f() 被調(diào)整為一個結(jié)果
被括號括起來的表達(dá)式永遠(yuǎn)被當(dāng)作一個值。
所以,
(f(x,y,z))
即使 f
返回多個值,
這個表達(dá)式永遠(yuǎn)是一個單一值。
((f(x,y,z))
的值是 f
返回的第一個值。
如果 f
不返回值的話,那么它的值就是 nil 。)
Lua 支持下列數(shù)學(xué)運算操作符:
+
: 加法-
: 減法*
: 乘法/
: 浮點除法//
: 向下取整除法%
: 取模^
: 乘方-
: 取負(fù)除了乘方和浮點除法運算, 數(shù)學(xué)運算按如下方式工作: 如果兩個操作數(shù)都是整數(shù), 該操作以整數(shù)方式操作且結(jié)果也將是一個整數(shù)。 否則,當(dāng)兩個操作數(shù)都是數(shù)字或可以被轉(zhuǎn)換為數(shù)字的字符串 (參見 §3.4.3)時, 操作數(shù)會被轉(zhuǎn)換成兩個浮點數(shù), 操作按通常的浮點規(guī)則(一般遵循 IEEE 754 標(biāo)準(zhǔn)) 來進(jìn)行,結(jié)果也是一個浮點數(shù)。
乘方和浮點除法 (/
)
總是把操作數(shù)轉(zhuǎn)換成浮點數(shù)進(jìn)行,其結(jié)果總是浮點數(shù)。
乘方使用 ISO C 函數(shù) pow
,
因此它也可以接受非整數(shù)的指數(shù)。
向下取整的除法 (//
)
指做一次除法,并將商圓整到靠近負(fù)無窮的一側(cè),
即對操作數(shù)做除法后取 floor 。
取模被定義成除法的余數(shù),其商被圓整到靠近負(fù)無窮的一側(cè)(向下取整的除法)。
對于整數(shù)數(shù)學(xué)運算的溢出問題, 這些操作采取的策略是按通常遵循的以 2 為補碼的數(shù)學(xué)運算的 環(huán)繞 規(guī)則。 (換句話說,它們返回其運算的數(shù)學(xué)結(jié)果對 264 取模后的數(shù)字。)
Lua 支持下列位操作符:
&
: 按位與|
: 按位或~
: 按位異或>>
: 右移<<
: 左移~
: 按位非所有的位操作都將操作數(shù)先轉(zhuǎn)換為整數(shù) (參見 §3.4.3), 然后按位操作,其結(jié)果是一個整數(shù)。
對于右移和左移,均用零來填補空位。 移動的位數(shù)若為負(fù),則向反方向位移; 若移動的位數(shù)的絕對值大于等于 整數(shù)本身的位數(shù),其結(jié)果為零 (所有位都被移出)。
Lua 對一些類型和值的內(nèi)部表示會在運行時做一些數(shù)學(xué)轉(zhuǎn)換。 位操作總是將浮點操作數(shù)轉(zhuǎn)換成整數(shù)。 乘方和浮點除法總是將整數(shù)轉(zhuǎn)換為浮點數(shù)。 其它數(shù)學(xué)操作若針對混合操作數(shù) (整數(shù)和浮點數(shù))將把整數(shù)轉(zhuǎn)換為浮點數(shù); 這一點被稱為 通常規(guī)則。 C API 同樣會按需把整數(shù)轉(zhuǎn)換為浮點數(shù)以及 把浮點數(shù)轉(zhuǎn)換為整數(shù)。 此外,字符串連接操作除了字符串,也可以接受數(shù)字作為參數(shù)。
當(dāng)操作需要數(shù)字時,Lua 還會把字符串轉(zhuǎn)換為數(shù)字。
當(dāng)把一個整數(shù)轉(zhuǎn)換為浮點數(shù)時, 若整數(shù)值恰好可以表示為一個浮點數(shù),那就取那個浮點數(shù)。 否則,轉(zhuǎn)換會取最接近的較大值或較小值來表示這個數(shù)。 這種轉(zhuǎn)換是不會失敗的。
將浮點數(shù)轉(zhuǎn)為整數(shù)的過程會檢查 浮點數(shù)能否被準(zhǔn)確的表達(dá)為一個整數(shù) (即,浮點數(shù)是一個整數(shù)值且在整數(shù)可以表達(dá)的區(qū)間)。 如果可以,結(jié)果就是那個數(shù),否則轉(zhuǎn)換失敗。
從字符串到數(shù)字的轉(zhuǎn)換過程遵循以下流程: 首先,遵循按 Lua 詞法分析器的規(guī)則分析語法來轉(zhuǎn)換為對應(yīng)的 整數(shù)或浮點數(shù)。 (字符串可以有前置或后置的空格以及一個符號。) 然后,結(jié)果數(shù)字再按前述規(guī)則轉(zhuǎn)換為所需要的類型(浮點或整數(shù))。
從數(shù)字轉(zhuǎn)換為字符串使用非指定的人可讀的格式。
若想完全控制數(shù)字到字符串的轉(zhuǎn)換過程,
可以使用字符串庫中的 format
函數(shù)
(參見 string.format
)。
Lua 支持下列比較操作符:
==
: 等于~=
: 不等于<
: 小于>
: 大于<=
: 小于等于>=
: 大于等于這些操作的結(jié)果不是 false 就是 true。
等于操作 (==
)先比較操作數(shù)的類型。
如果類型不同,結(jié)果就是 false。
否則,繼續(xù)比較值。
字符串按一般的方式比較。
數(shù)字遵循二元操作的規(guī)則:
如果兩個操作數(shù)都是整數(shù),
它們按整數(shù)比較;
否則,它們先轉(zhuǎn)換為浮點數(shù),然后再做比較。
表,用戶數(shù)據(jù),以及線程都按引用比較: 只有兩者引用同一個對象時才認(rèn)為它們相等。 每次你創(chuàng)建一個新對象(一張表,一個用戶數(shù)據(jù),或一個線程), 新對象都一定和已有且存在的對象不同。 相同引用的閉包一定相等。 有任何可察覺的差異(不同的行為,不同的定義)一定不等。
你可以通過使用 "eq" 元方法(參見 §2.4) 來改變 Lua 比較表和用戶數(shù)據(jù)時的方式。
等于操作不會將字符串轉(zhuǎn)換為數(shù)字,反之亦然。
即,"0"==0
結(jié)果為 false,
且 t[0]
與 t["0"]
指代著表中的不同項。
~=
操作完全等價于 (==
) 操作的反值。
大小比較操作以以下方式進(jìn)行。
如果參數(shù)都是數(shù)字,
它們按二元操作的常規(guī)進(jìn)行。
否則,如果兩個參數(shù)都是字符串,
它們的值按當(dāng)前的區(qū)域設(shè)置來比較。
再則,Lua 就試著調(diào)用 "lt" 或是 "le" 元方法
(參見 §2.4)。
a > b
的比較被轉(zhuǎn)譯為 b < a
,
a >= b
被轉(zhuǎn)譯為 b <= a
。
Lua 中的邏輯操作符有 and, or,以及 not。 和控制結(jié)構(gòu)(參見 §3.3.4)一樣, 所有的邏輯操作符把 false 和 nil 都作為假, 而其它的一切都當(dāng)作真。
取反操作 not 總是返回 false 或 true 中的一個。 與操作符 and 在第一個參數(shù)為 false 或 nil 時 返回這第一個參數(shù); 否則,and 返回第二個參數(shù)。 或操作符 or 在第一個參數(shù)不為 nil 也不為 false 時, 返回這第一個參數(shù),否則返回第二個參數(shù)。 and 和 or 都遵循短路規(guī)則; 也就是說,第二個操作數(shù)只在需要的時候去求值。 這里有一些例子:
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
(在這本手冊中,
-->
指前面表達(dá)式的結(jié)果。)
Lua 中字符串的連接操作符寫作兩個點('..
')。
如果兩個操作數(shù)都是字符串或都是數(shù)字,
連接操作將以 §3.4.3 中提到的規(guī)則把其轉(zhuǎn)換為字符串。
否則,會調(diào)用元方法 __concat
(參見 §2.4)。
取長度操作符寫作一元前置符 #
。
字符串的長度是它的字節(jié)數(shù)(就是以一個字符一個字節(jié)計算的字符串長度)。
程序可以通過 __len
元方法(參見 §2.4)
來修改對字符串類型外的任何值的取長度操作行為。
如果 __len
元方法沒有給出,
表 t
的長度只在表是一個 序列 時有定義。
序列指表的正數(shù)鍵集等于 {1..n} ,
其中 n 是一個非負(fù)整數(shù)。
在這種情況下,n 是表的長度。
注意這樣的表
{10, 20, nil, 40}
不是一個序列,因為它有鍵 4
卻沒有鍵 3
。
(因此,該表的正整數(shù)鍵集不等于 {1..n} 集合,故而就不存在 n。)
注意,一張表是否是一個序列和它的非數(shù)字鍵無關(guān)。
Lua 中操作符的優(yōu)先級寫在下表中,從低到高優(yōu)先級排序:
or and < > <= >= ~= == | ~ & << >> .. + - * / // % unary operators (not # - ~) ^
通常,
你可以用括號來改變運算次序。
連接操作符 ('..
') 和乘方操作 ('^
')
是從右至左的。
其它所有的操作都是從左至右。
表構(gòu)造子是一個構(gòu)造表的表達(dá)式。 每次構(gòu)造子被執(zhí)行,都會構(gòu)造出一張新的表。 構(gòu)造子可以被用來構(gòu)造一張空表, 也可以用來構(gòu)造一張表并初始化其中的一些域。 一般的構(gòu)造子的語法如下
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 開始不斷增長的數(shù)字。
這這個格式中的其它域不會破壞其記數(shù)。
舉個例子:
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
構(gòu)造子中賦值的次序未定義。 (次序問題只會對那些鍵重復(fù)時的情況有影響。)
如果表單中最后一個域的形式是 exp
,
而且其表達(dá)式是一個函數(shù)調(diào)用或者是一個可變參數(shù),
那么這個表達(dá)式所有的返回值將依次進(jìn)入列表
(參見 §3.4.10)。
初始化域表可以在最后多一個分割符, 這樣設(shè)計可以方便由機器生成代碼。
Lua 中的函數(shù)調(diào)用的語法如下:
functioncall ::= prefixexp args
函數(shù)調(diào)用時, 第一步,prefixexp 和 args 先被求值。 如果 prefixexp 的值的類型是 function, 那么這個函數(shù)就被用給出的參數(shù)調(diào)用。 否則 prefixexp 的元方法 "call" 就被調(diào)用, 第一個參數(shù)是 prefixexp 的值, 接下來的是原來的調(diào)用參數(shù) (參見 §2.4)。
這樣的形式
functioncall ::= prefixexp ‘:’ Name args
可以用來調(diào)用 "方法"。
這是 Lua 支持的一種語法糖。
像 v:name(args)
這個樣子,
被解釋成 v.name(v,args)
,
這里的 v
只會被求值一次。
參數(shù)的語法如下:
args ::= ‘(’ [explist] ‘)’ args ::= tableconstructor args ::= LiteralString
所有參數(shù)的表達(dá)式求值都在函數(shù)調(diào)用之前。
這樣的調(diào)用形式 f{fields}
是一種語法糖用于表示
f({fields})
;
這里指參數(shù)列表是一個新創(chuàng)建出來的列表。
而這樣的形式 f'string'
(或是 f"string"
亦或是 f[[string]]
)
也是一種語法糖,用于表示 f('string')
;
此時的參數(shù)列表是一個單獨的字符串。
return functioncall
這樣的調(diào)用形式將觸發(fā)一次 尾調(diào)用。
Lua 實現(xiàn)了 完全尾調(diào)用(或稱為 完全尾遞歸):
在尾調(diào)用中, 被調(diào)用的函數(shù)重用調(diào)用它的函數(shù)的堆棧項。
因此,對于程序執(zhí)行的嵌套尾調(diào)用的層數(shù)是沒有限制的。
然而,尾調(diào)用將刪除調(diào)用它的函數(shù)的任何調(diào)試信息。
注意,尾調(diào)用只發(fā)生在特定的語法下,
僅當(dāng) return 只有單一函數(shù)調(diào)用作為參數(shù)時才發(fā)生尾調(diào)用;
這種語法使得調(diào)用函數(shù)的所有結(jié)果可以完整地返回。
因此,下面這些例子都不是尾調(diào)用:
return (f(x)) -- 返回值被調(diào)整為一個 return 2 * f(x) return x, f(x) -- 追加若干返回值 f(x); return -- 返回值全部被舍棄 return x or f(x) -- 返回值被調(diào)整為一個
函數(shù)定義的語法如下:
functiondef ::= function funcbody funcbody ::= ‘(’ [parlist] ‘)’ block end
另外定義了一些語法糖簡化函數(shù)定義的寫法:
stat ::= function funcname funcbody stat ::= local function Name funcbody funcname ::= Name {‘.’ Name} [‘:’ Name]
該語句
function f () body end
被轉(zhuǎn)譯成
f = function () body end
該語句
function t.a.b.c.f () body end
被轉(zhuǎn)譯成
t.a.b.c.f = function () body end
該語句
local function f () body end
被轉(zhuǎn)譯成
local f; f = function () body end
而不是
local f = function () body end
(這個差別只在函數(shù)體內(nèi)需要引用 f
時才有。)
一個函數(shù)定義是一個可執(zhí)行的表達(dá)式, 執(zhí)行結(jié)果是一個類型為 function 的值。 當(dāng) Lua 預(yù)編譯一個代碼塊時, 代碼塊作為一個函數(shù),整個函數(shù)體也就被預(yù)編譯了。 那么,無論何時 Lua 執(zhí)行了函數(shù)定義, 這個函數(shù)本身就進(jìn)行了 實例化(或者說是 關(guān)閉了)。 這個函數(shù)的實例(或者說是 閉包)是表達(dá)式的最終值。
形參被看作是一些局部變量, 它們將由實參的值來初始化:
parlist ::= namelist [‘,’ ‘...’] | ‘...’
當(dāng)一個函數(shù)被調(diào)用,
如果函數(shù)并非一個 可變參數(shù)函數(shù),
即在形參列表的末尾注明三個點 ('...
'),
那么實參列表就會被調(diào)整到形參列表的長度。
變長參數(shù)函數(shù)不會調(diào)整實參列表;
取而代之的是,它將把所有額外的參數(shù)放在一起通過
變長參數(shù)表達(dá)式傳遞給函數(shù),
其寫法依舊是三個點。
這個表達(dá)式的值是一串實參值的列表,
看起來就跟一個可以返回多個結(jié)果的函數(shù)一樣。
如果一個變長參數(shù)表達(dá)式放在另一個表達(dá)式中使用,
或是放在另一串表達(dá)式的中間,
那么它的返回值就會被調(diào)整為單個值。
若這個表達(dá)式放在了一系列表達(dá)式的最后一個,
就不會做調(diào)整了
(除非這最后一個參數(shù)被括號給括了起來)。
我們先做如下定義,然后再來看一個例子:
function f(a, b) end function g(a, b, ...) end function r() return 1,2,3 end
下面看看實參到形參數(shù)以及可變長參數(shù)的映射關(guān)系:
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
結(jié)果由 return 來返回(參見 §3.3.4)。 如果執(zhí)行到函數(shù)末尾依舊沒有遇到任何 return 語句, 函數(shù)就不會返回任何結(jié)果。
關(guān)于函數(shù)可返回值的數(shù)量限制和系統(tǒng)有關(guān)。 這個限制一定大于 1000 。
冒號 語法可以用來定義 方法,
就是說,函數(shù)可以有一個隱式的形參 self
。
因此,如下語句
function t.a.b.c:f (params) body end
是這樣一種寫法的語法糖
t.a.b.c.f = function (self, params) body end
Lua 語言有詞法作用范圍。 變量的作用范圍開始于聲明它們之后的第一個語句段, 結(jié)束于包含這個聲明的最內(nèi)層語句塊的最后一個非空語句。 看下面這些例子:
x = 10 -- 全局變量 do -- 新的語句塊 local x = x -- 新的一個 'x', 它的值現(xiàn)在是 10 print(x) --> 10 x = x+1 do -- 另一個語句塊 local x = x+1 -- 又一個 'x' print(x) --> 12 end print(x) --> 11 end print(x) --> 10 (取到的是全局的那一個)
注意這里,類似 local x = x
這樣的聲明,
新的 x
正在被聲明,但是還沒有進(jìn)入它的作用范圍,
所以第二個 x
指向的是外面一層的變量。
因為有這樣一個詞法作用范圍的規(guī)則, 局部變量可以被在它的作用范圍內(nèi)定義的函數(shù)自由使用。 當(dāng)一個局部變量被內(nèi)層的函數(shù)中使用的時候, 它被內(nèi)層函數(shù)稱作 上值,或是 外部局部變量。
注意,每次執(zhí)行到一個 local 語句都會定義出一個新的局部變量。 看看這樣一個例子:
a = {} local x = 20 for i=1,10 do local y = 0 a[i] = function () y=y+1; return x+y end end
這個循環(huán)創(chuàng)建了十個閉包(這指十個匿名函數(shù)的實例)。
這些閉包中的每一個都使用了不同的 y
變量,
而它們又共享了同一份 x
。
這個部分描述了 Lua 的 C API ,
也就是宿主程序跟 Lua 通訊用的一組 C 函數(shù)。
所有的 API 函數(shù)按相關(guān)的類型以及常量都聲明在頭文件
lua.h
中。
雖然我們說的是“函數(shù)”, 但一部分簡單的 API 是以宏的形式提供的。 除非另有說明, 所有的這些宏都只使用它們的參數(shù)一次 (除了第一個參數(shù),那一定是 Lua 狀態(tài)), 因此你不需擔(dān)心這些宏的展開會引起一些副作用。
C 庫中所有的 Lua API 函數(shù)都不去檢查參數(shù)是否相容及有效。
然而,你可以在編譯 Lua 時加上打開一個宏開關(guān)
LUA_USE_APICHECK
來改變這個行為。
Lua 使用一個 虛擬棧 來和 C 互傳值。 棧上的的每個元素都是一個 Lua 值 (nil,數(shù)字,字符串,等等)。
無論何時 Lua 調(diào)用 C,被調(diào)用的函數(shù)都得到一個新的棧,
這個棧獨立于 C 函數(shù)本身的棧,也獨立于之前的 Lua 棧。
它里面包含了 Lua 傳遞給 C 函數(shù)的所有參數(shù),
而 C 函數(shù)則把要返回的結(jié)果放入這個棧以返回給調(diào)用者
(參見 lua_CFunction
)。
方便起見, 所有針對棧的 API 查詢操作都不嚴(yán)格遵循棧的操作規(guī)則。 而是可以用一個 索引 來指向棧上的任何元素: 正的索引指的是棧上的絕對位置(從1開始); 負(fù)的索引則指從棧頂開始的偏移量。 展開來說,如果堆棧有 n 個元素, 那么索引 1 表示第一個元素 (也就是最先被壓棧的元素) 而索引 n 則指最后一個元素; 索引 -1 也是指最后一個元素 (即棧頂?shù)脑兀? 索引 -n 是指第一個元素。
當(dāng)你使用 Lua API 時,
就有責(zé)任保證做恰當(dāng)?shù)恼{(diào)用。
特別需要注意的是,
你有責(zé)任控制不要堆棧溢出。
你可以使用 lua_checkstack
這個函數(shù)來擴(kuò)大可用堆棧的尺寸。
無論何時 Lua 調(diào)用 C ,
它都只保證至少有
LUA_MINSTACK
這么多的堆棧空間可以使用。
LUA_MINSTACK
一般被定義為 20 ,
因此,只要你不是不斷的把數(shù)據(jù)壓棧,
通常你不用關(guān)心堆棧大小。
當(dāng)你調(diào)用一個 Lua 函數(shù)卻沒有指定要接收多少個返回值時
(參見 lua_call
),
Lua 可以保證棧一定有足夠的空間來接收所有的返回值,
但不保證此外留有額外的空間。
因此,在做了一次這樣的調(diào)用后,如果你需要繼續(xù)壓棧,
則需要使用 lua_checkstack
。
API 中的函數(shù)若需要傳入棧索引,這個索引必須是 有效索引 或是 可接受索引。
有效索引 指引用棧內(nèi)真實位置的索引;
即在 1 到棧頂之間的位置
(1 ≤ abs(index) ≤ top
)。
通常,一個可能修改該位置的值的函數(shù)需要傳入有效索引。
除非另有說明, 任何可以接受有效索引的函數(shù)同時也接受 偽索引。 偽索引指代一些可以被 C code 訪問得到 Lua 值,而它們又不在棧內(nèi)。 這用于訪問注冊表以及 C 函數(shù)的上值(參見 §4.4)。
對于那些只是需要棧中的值(例如查詢函數(shù)) 而不需要指定一個棧位置的函數(shù), 可以用一個可接受的索引去調(diào)用它們。 可接受索引 不僅可以是任何包括偽索引在內(nèi)的有效索引, 還可以是任何超過棧頂?shù)湓跒闂7峙涑鰜淼目臻g內(nèi)的正索引。 (注意 0 永遠(yuǎn)都不是一個可接受索引。) 除非另有說明,API 里的函數(shù)都接受可接受索引。
允許可接受索引是為了避免對棧頂以外的查詢時做額外的檢查。 例如,C 函數(shù)可以直接查詢傳給它的第三個參數(shù), 而不用先檢查是不是有第三個參數(shù), 即不需要檢查 3 是不是一個有效索引。
對于那可以接受索引調(diào)用的函數(shù),
無效索引被看作包含了一個虛擬類型
LUA_TNONE
的值,
這個值的行為和 nil 一致。
當(dāng) C 函數(shù)被創(chuàng)建出來,
我們有可能會把一些值關(guān)聯(lián)在一起,
也就是創(chuàng)建一個 C 閉包
(參見 lua_pushcclosure
);
這些被關(guān)聯(lián)起來的值被叫做 上值 ,
它們可以在函數(shù)被調(diào)用的時候訪問的到。
無論何時去調(diào)用 C 函數(shù),
函數(shù)的上值都可以用偽索引定位。
我們可以用
lua_upvalueindex
這個宏來生成這些偽索引。
第一個關(guān)聯(lián)到函數(shù)的值放在
lua_upvalueindex(1)
位置處,依此類推。
使用 lua_upvalueindex(n)
時,
若 n 大于當(dāng)前函數(shù)的總上值個數(shù)
(但不可以大于 256)會產(chǎn)生一個可接受的但無效的索引。
Lua 提供了一個 注冊表,
這是一個預(yù)定義出來的表,
可以用來保存任何 C 代碼想保存的 Lua 值。
這個表可以用有效偽索引
LUA_REGISTRYINDEX
來定位。
任何 C 庫都可以在這張表里保存數(shù)據(jù),
為了防止沖突,你需要特別小心的選擇鍵名。
一般的用法是,你可以用一個包含你的庫名的字符串做為鍵名,
或者取你自己 C 對象的地址,以輕量用戶數(shù)據(jù)的形式做鍵,
還可以用你的代碼創(chuàng)建出來的任意 Lua 對象做鍵。
關(guān)于變量名,字符串鍵名中以下劃線加大寫字母的名字被 Lua 保留。
注冊表中的整數(shù)鍵用于引用機制
(參見 luaL_ref
),
以及一些預(yù)定義的值。
因此,整數(shù)鍵不要用于別的目的。
當(dāng)你創(chuàng)建了一個新的 Lua 狀態(tài)機,
其中的注冊表內(nèi)就預(yù)定義好了幾個值。
這些預(yù)定義值可以用整數(shù)索引到,
這些整數(shù)以常數(shù)形式定義在 lua.h
中。
有下列常數(shù):
LUA_RIDX_MAINTHREAD
:
注冊表中這個索引下是狀態(tài)機的主線程。
(主線程和狀態(tài)機同時被創(chuàng)建出來。)
LUA_RIDX_GLOBALS
:
注冊表的這個索引下是全局環(huán)境。
在內(nèi)部實現(xiàn)中,Lua 使用了 C 的 longjmp
機制來處理錯誤。
(如果你使用 C++ 編譯,Lua 將換成異常;
細(xì)節(jié)請在源代碼中搜索 LUAI_THROW
。)
當(dāng) Lua 碰到任何錯誤
(比如內(nèi)存分配錯誤、類型錯誤、語法錯誤、還有運行時錯誤)
它都會 拋出一個錯誤出去;
也就是調(diào)用一次長跳轉(zhuǎn)。
在 保護(hù)環(huán)境 下,
Lua 使用 setjmp
來設(shè)置一個恢復(fù)點;
任何發(fā)生的錯誤都會跳轉(zhuǎn)到最近的一個恢復(fù)點。
如果錯誤發(fā)生在保護(hù)環(huán)境之外,
Lua 會先調(diào)用 panic 函數(shù) (參見 lua_atpanic
)
然后調(diào)用 abort
來退出宿主程序。
你的 panic 函數(shù)只要不返回
(例如:長跳轉(zhuǎn)到你在 Lua 外你自己設(shè)置的恢復(fù)點)
就可以不退出程序。
panic 函數(shù)以錯誤消息處理器(參見 §2.3)的方式運行; 錯誤消息在棧頂。 不同的是,它不保證棧空間。 做任何壓棧操作前,panic 函數(shù)都必須先檢查是否有足夠的空間 (參見 §4.2)。
大多數(shù) API 函數(shù)都有可能拋出錯誤, 例如在內(nèi)存分配錯誤時就會拋出。 每個函數(shù)的文檔都會注明它是否可能拋出錯誤。
在 C 函數(shù)內(nèi)部,你可以通過調(diào)用 lua_error
來拋出錯誤。
Lua 內(nèi)部使用 C 的 longjmp
機制讓出一個協(xié)程。
因此,如果一個 C 函數(shù) foo
調(diào)用了一個 API 函數(shù),
而這個 API 函數(shù)讓出了(直接或間接調(diào)用了讓出函數(shù))。
由于 longjmp
會移除 C 棧的棧幀,
Lua 就無法返回到 foo
里了。
為了回避這類問題,
碰到 API 調(diào)用中調(diào)用讓出時,除了那些拋出錯誤的 API 外,還提供了三個函數(shù):
lua_yieldk
,
lua_callk
,和 lua_pcallk
。
它們在讓出發(fā)生時,可以從傳入的 延續(xù)函數(shù)
(名為 k
的參數(shù))繼續(xù)運行。
我們需要預(yù)設(shè)一些術(shù)語來解釋延續(xù)點。
對于從 Lua 中調(diào)用的 C 函數(shù),我們稱之為 原函數(shù)。
從這個原函數(shù)中調(diào)用的上面所述的三個 C API 函數(shù)我們稱之為 被調(diào)函數(shù)。
被調(diào)函數(shù)可以使當(dāng)前線程讓出。
(讓出發(fā)生在被調(diào)函數(shù)是 lua_yieldk
,
或傳入 lua_callk
或
lua_pcallk
的函數(shù)調(diào)用了讓出時。)
假設(shè)正在運行的線程在執(zhí)行被調(diào)函數(shù)時讓出。 當(dāng)再次延續(xù)這條線程,它希望繼續(xù)被調(diào)函數(shù)的運行。 然而,被調(diào)函數(shù)不可能返回到原函數(shù)中。 這是因為之前的讓出操作破壞了 C 棧的棧幀。 作為替代品,Lua 調(diào)用那個作為被調(diào)函數(shù)參數(shù)給出的 延續(xù)函數(shù) 。 正如其名,延續(xù)函數(shù)將延續(xù)原函數(shù)的任務(wù)。
下面的函數(shù)會做一個說明:
int original_function (lua_State *L) { ... /* code 1 */ status = lua_pcall(L, n, m, h); /* calls Lua */ ... /* code 2 */ }
現(xiàn)在我們想允許被
lua_pcall
運行的 Lua 代碼讓出。
首先,我們把函數(shù)改寫成這個樣子:
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); }
上面的代碼中,新函數(shù) k
就是一個 延續(xù)函數(shù)
(函數(shù)類型為 lua_KFunction
)。
它的工作就是原函數(shù)中調(diào)用 lua_pcall
之后做的那些事情。
現(xiàn)在我們必須通知 Lua 說,你必須在被
lua_pcall
執(zhí)行的 Lua 代碼發(fā)生過中斷(錯誤或讓出)后,
還得繼續(xù)調(diào)用 k
。
所以我們還得繼續(xù)改寫這段代碼,把
lua_pcall
替換成
lua_pcallk
:
int original_function (lua_State *L) { ... /* code 1 */ return k(L, lua_pcallk(L, n, m, h, ctx2, k), ctx1); }
注意這里那個額外的顯式的對延續(xù)函數(shù)的調(diào)用:
Lua 僅在需要時,這可能是由錯誤導(dǎo)致的也可能是發(fā)生了讓出而需要繼續(xù)運行,才會調(diào)用延續(xù)函數(shù)。
如果沒有發(fā)生過任何讓出,調(diào)用的函數(shù)正常返回,
那么 lua_pcallk
(以及 lua_callk
)也會正常返回。
(當(dāng)然,這個例子中你也可以不在之后調(diào)用延續(xù)函數(shù),
而是在原函數(shù)的調(diào)用后直接寫上需要做的工作。)
除了 Lua 狀態(tài),延續(xù)函數(shù)還有兩個參數(shù):
一個是調(diào)用最后的狀態(tài)碼,另一個一開始由
lua_pcallk
傳入的上下文
(ctx
)。
(Lua 本身不使用這個值;它僅僅從原函數(shù)轉(zhuǎn)發(fā)這個值給延續(xù)函數(shù)。)
對于 lua_pcallk
而言,
狀態(tài)碼和 lua_pcallk
本應(yīng)返回值相同,區(qū)別僅在于發(fā)生過讓出后才執(zhí)行完時,狀態(tài)碼為
LUA_YIELD
(而不是
LUA_OK
)。
對于 lua_yieldk
和
lua_callk
而言,
調(diào)用延續(xù)函數(shù)傳入的狀態(tài)碼一定是
LUA_YIELD
。
(對這兩個函數(shù),Lua 不會因任何錯誤而調(diào)用延續(xù)函數(shù)。
因為它們并不處理錯誤。)
同樣,當(dāng)你使用 lua_callk
時,
你應(yīng)該用 LUA_OK
作為狀態(tài)碼來調(diào)用延續(xù)函數(shù)。
(對于 lua_yieldk
,
幾乎沒有什么地方需要直接調(diào)用延續(xù)函數(shù),
因為 lua_yieldk
本身并不會返回。)
Lua 會把延續(xù)函數(shù)看作原函數(shù)。
延續(xù)函數(shù)將接收到和原函數(shù)相同的 Lua 棧,其接收到的 lua 狀態(tài)也和
被調(diào)函數(shù)若返回后應(yīng)該有的狀態(tài)一致。
(例如,
lua_callk
調(diào)用之后,
棧中之前壓入的函數(shù)和調(diào)用參數(shù)都被調(diào)用產(chǎn)生的返回值所替代。)
這時也有相同的上值。
等到它返回的時候,Lua 會將其看待成原函數(shù)的返回去操作。
這里按字母次序列出了所有 C API 中的函數(shù)和類型。 每個函數(shù)都有一個這樣的提示: [-o, +p, x]
對于第一個域,o
,
指的是該函數(shù)會從棧上彈出多少個元素。
第二個域,p
,
指該函數(shù)會將多少個元素壓棧。
(所有函數(shù)都會在彈出參數(shù)后再把結(jié)果壓棧。)
x|y
這種形式的域表示該函數(shù)根據(jù)具體情況可能壓入(或彈出)
x
或 y
個元素;
問號 '?
' 表示
我們無法僅通過參數(shù)來了解該函數(shù)會彈出/壓入多少元素
(比如,數(shù)量取決于棧上有些什么)。
第三個域,x
,
解釋了該函數(shù)是否會拋出錯誤:
'-
' 表示該函數(shù)絕對不會拋出錯誤;
'e
' 表示該函數(shù)可能拋出錯誤;
'v
' 表示該函數(shù)可能拋出有意義的錯誤。
lua_absindex
[-0, +0, –]
int lua_absindex (lua_State *L, int idx);
將一個可接受的索引 idx
轉(zhuǎn)換為絕對索引
(即,一個不依賴棧頂在哪的值)。
lua_Alloc
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
Lua 狀態(tài)機中使用的內(nèi)存分配器函數(shù)的類型。
內(nèi)存分配函數(shù)必須提供一個功能類似于 realloc
但又不完全相同的函數(shù)。
它的參數(shù)有
ud
,一個由 lua_newstate
傳給它的指針;
ptr
,一個指向已分配出來/將被重新分配/要釋放的內(nèi)存塊指針;
osize
,內(nèi)存塊原來的尺寸或是關(guān)于什么將被分配出來的代碼;
nsize
,新內(nèi)存塊的尺寸。
如果 ptr
不是 NULL
,
osize
是 ptr
指向的內(nèi)存塊的尺寸,
即這個內(nèi)存塊當(dāng)初被分配或重分配的尺寸。
如果 ptr
是 NULL
,
osize
是 Lua 即將分配對象類型的編碼。
當(dāng)(且僅當(dāng))Lua 創(chuàng)建一個對應(yīng)類型的新對象時,
osize
是
LUA_TSTRING
,LUA_TTABLE
,LUA_TFUNCTION
,
LUA_TUSERDATA
,或 LUA_TTHREAD
中的一個。
若 osize
是其它類型,Lua 將為其它東西分配內(nèi)存。
Lua 假定分配器函數(shù)會遵循以下行為:
當(dāng) nsize
是零時,
分配器必須和 free
行為類似并返回 NULL
。
當(dāng) nsize
不是零時,
分配器必須和 realloc
行為類似。
如果分配器無法完成請求,返回 NULL
。
Lua 假定在 osize >= nsize
成立的條件下,
分配器絕不會失敗。
這里有一個簡單的分配器函數(shù)的實現(xiàn)。
這個實現(xiàn)被放在補充庫中,供
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); }
注意,標(biāo)準(zhǔn) C 能確保 free(NULL)
沒有副作用,
且 realloc(NULL,size)
等價于 malloc(size)
。
這段代碼假定 realloc
在縮小塊長度時不會失敗。
(雖然標(biāo)準(zhǔn) C 沒有對此行為做出保證,但這看起來是一個安全的假定。)
lua_arith
[-(2|1), +1, e]
void lua_arith (lua_State *L, int op);
對棧頂?shù)膬蓚€值(或者一個,比如取反)做一次數(shù)學(xué)或位操作。 其中,棧頂?shù)哪莻€值是第二個操作數(shù)。 它會彈出壓入的值,并把結(jié)果放在棧頂。 這個函數(shù)遵循 Lua 對應(yīng)的操作符運算規(guī)則 (即有可能觸發(fā)元方法)。
op
的值必須是下列常量中的一個:
LUA_OPADD
: 加法 (+
)LUA_OPSUB
: 減法 (-
)LUA_OPMUL
: 乘法 (*
)LUA_OPDIV
: 浮點除法 (/
)LUA_OPIDIV
: 向下取整的除法 (//
)LUA_OPMOD
: 取模 (%
)LUA_OPPOW
: 乘方 (^
)LUA_OPUNM
: 取負(fù) (一元 -
)LUA_OPBNOT
: 按位取反 (~
)LUA_OPBAND
: 按位與 (&
)LUA_OPBOR
: 按位或 (|
)LUA_OPBXOR
: 按位異或 (~
)LUA_OPSHL
: 左移 (<<
)LUA_OPSHR
: 右移 (>>
)lua_atpanic
[-0, +0, –]
lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);
設(shè)置一個新的 panic 函數(shù),并返回之前設(shè)置的那個。 (參見 §4.6)。
lua_call
[-(nargs+1), +nresults, e]
void lua_call (lua_State *L, int nargs, int nresults);
調(diào)用一個函數(shù)。
要調(diào)用一個函數(shù)請遵循以下協(xié)議:
首先,要調(diào)用的函數(shù)應(yīng)該被壓入棧;
接著,把需要傳遞給這個函數(shù)的參數(shù)按正序壓棧;
這是指第一個參數(shù)首先壓棧。
最后調(diào)用一下 lua_call
;
nargs
是你壓入棧的參數(shù)個數(shù)。
當(dāng)函數(shù)調(diào)用完畢后,所有的參數(shù)以及函數(shù)本身都會出棧。
而函數(shù)的返回值這時則被壓棧。
返回值的個數(shù)將被調(diào)整為 nresults
個,
除非 nresults
被設(shè)置成 LUA_MULTRET
。
在這種情況下,所有的返回值都被壓入堆棧中。
Lua 會保證返回值都放入??臻g中。
函數(shù)返回值將按正序壓棧(第一個返回值首先壓棧),
因此在調(diào)用結(jié)束后,最后一個返回值將被放在棧頂。
被調(diào)用函數(shù)內(nèi)發(fā)生的錯誤將(通過 longjmp
)一直上拋。
下面的例子中,這行 Lua 代碼等價于在宿主程序中用 C 代碼做一些工作:
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' */
注意上面這段代碼是 平衡 的: 到了最后,堆?;謴?fù)成原有的配置。 這是一種良好的編程習(xí)慣。
lua_callk
[-(nargs + 1), +nresults, e]
void lua_callk (lua_State *L, int nargs, int nresults, lua_KContext ctx, lua_KFunction k);
這個函數(shù)的行為和 lua_call
完全一致,只不過它還允許被調(diào)用的函數(shù)讓出
(參見 §4.7)。
lua_CFunction
typedef int (*lua_CFunction) (lua_State *L);
C 函數(shù)的類型。
為了正確的和 Lua 通訊,
C 函數(shù)必須使用下列協(xié)議。
這個協(xié)議定義了參數(shù)以及返回值傳遞方法:
C 函數(shù)通過 Lua 中的棧來接受參數(shù),
參數(shù)以正序入棧(第一個參數(shù)首先入棧)。
因此,當(dāng)函數(shù)開始的時候,
lua_gettop(L)
可以返回函數(shù)收到的參數(shù)個數(shù)。
第一個參數(shù)(如果有的話)在索引 1 的地方,
而最后一個參數(shù)在索引 lua_gettop(L)
處。
當(dāng)需要向 Lua 返回值的時候,
C 函數(shù)只需要把它們以正序壓到堆棧上(第一個返回值最先壓入),
然后返回這些返回值的個數(shù)。
在這些返回值之下的,堆棧上的東西都會被 Lua 丟掉。
和 Lua 函數(shù)一樣,從 Lua 中調(diào)用 C 函數(shù)也可以有很多返回值。
下面這個例子中的函數(shù)將接收若干數(shù)字參數(shù),并返回它們的平均數(shù)與和:
static int foo (lua_State *L) { int n = lua_gettop(L); /* 參數(shù)的個數(shù) */ 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); /* 第一個返回值 */ lua_pushnumber(L, sum); /* 第二個返回值 */ return 2; /* 返回值的個數(shù) */ }
lua_checkstack
[-0, +0, –]
int lua_checkstack (lua_State *L, int n);
確保堆棧上至少有 n
個額外空位。
如果不能把堆棧擴(kuò)展到相應(yīng)的尺寸,函數(shù)返回假。
失敗的原因包括將把棧擴(kuò)展到比固定最大尺寸還大
(至少是幾千個元素)或分配內(nèi)存失敗。
這個函數(shù)永遠(yuǎn)不會縮小堆棧;
如果堆棧已經(jīng)比需要的大了,那么就保持原樣。
lua_close
[-0, +0, –]
void lua_close (lua_State *L);
銷毀指定 Lua 狀態(tài)機中的所有對象 (如果有垃圾收集相關(guān)的元方法的話,會調(diào)用它們), 并且釋放狀態(tài)機中使用的所有動態(tài)內(nèi)存。 在一些平臺上,你可以不必調(diào)用這個函數(shù), 因為當(dāng)宿主程序結(jié)束的時候,所有的資源就自然被釋放掉了。 另一方面,長期運行的程序,比如一個后臺程序或是一個網(wǎng)站服務(wù)器, 會創(chuàng)建出多個 Lua 狀態(tài)機。那么就應(yīng)該在不需要時趕緊關(guān)閉它們。
lua_compare
[-0, +0, e]
int lua_compare (lua_State *L, int index1, int index2, int op);
比較兩個 Lua 值。
當(dāng)索引 index1
處的值通過 op
和索引 index2
處的值做比較后條件滿足,函數(shù)返回 1 。
這個函數(shù)遵循 Lua 對應(yīng)的操作規(guī)則(即有可能觸發(fā)元方法)。
反之,函數(shù)返回 0。
當(dāng)任何一個索引無效時,函數(shù)也會返回 0 。
op
值必須是下列常量中的一個:
lua_concat
[-n, +1, e]
void lua_concat (lua_State *L, int n);
連接棧頂?shù)?n
個值,
然后將這些值出棧,并把結(jié)果放在棧頂。
如果 n
為 1 ,結(jié)果就是那個值放在棧上(即,函數(shù)什么都不做);
如果 n
為 0 ,結(jié)果是一個空串。
連接依照 Lua 中通常語義完成(參見 §3.4.6 )。
lua_copy
[-0, +0, –]
void lua_copy (lua_State *L, int fromidx, int toidx);
從索引 fromidx
處復(fù)制一個值到一個有效索引
toidx
處,覆蓋那里的原有值。
不會影響其它位置的值。
lua_createtable
[-0, +1, e]
void lua_createtable (lua_State *L, int narr, int nrec);
創(chuàng)建一張新的空表壓棧。
參數(shù) narr
建議了這張表作為序列使用時會有多少個元素;
參數(shù) nrec
建議了這張表可能擁有多少序列之外的元素。
Lua 會使用這些建議來預(yù)分配這張新表。
如果你知道這張表用途的更多信息,預(yù)分配可以提高性能。
否則,你可以使用函數(shù) lua_newtable
。
lua_dump
[-0, +0, e]
int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip);
把函數(shù)導(dǎo)出成二進(jìn)制代碼塊 。
函數(shù)接收棧頂?shù)?Lua 函數(shù)做參數(shù),
然后生成它的二進(jìn)制代碼塊。
若被導(dǎo)出的東西被再次加載,
加載的結(jié)果就相當(dāng)于原來的函數(shù)。
當(dāng)它在產(chǎn)生代碼塊的時候,
lua_dump
通過調(diào)用函數(shù) writer
(參見 lua_Writer
)
來寫入數(shù)據(jù),后面的 data
參數(shù)會被傳入 writer
。
如果 strip
為真,
二進(jìn)制代碼塊將不包含該函數(shù)的調(diào)試信息。
最后一次由 writer
的返回值將作為這個函數(shù)的返回值返回;
0 表示沒有錯誤。
該函數(shù)不會把 Lua 函數(shù)彈出堆棧。
lua_error
[-1, +0, v]
int lua_error (lua_State *L);
以棧頂?shù)闹底鳛殄e誤對象,拋出一個 Lua 錯誤。
這個函數(shù)將做一次長跳轉(zhuǎn),所以一定不會返回
(參見 luaL_error
)。
lua_gc
[-0, +0, e]
int lua_gc (lua_State *L, int what, int data);
控制垃圾收集器。
這個函數(shù)根據(jù)其參數(shù) what
發(fā)起幾種不同的任務(wù):
LUA_GCSTOP
:
停止垃圾收集器。
LUA_GCRESTART
:
重啟垃圾收集器。
LUA_GCCOLLECT
:
發(fā)起一次完整的垃圾收集循環(huán)。
LUA_GCCOUNT
:
返回 Lua 使用的內(nèi)存總量(以 K 字節(jié)為單位)。
LUA_GCCOUNTB
:
返回當(dāng)前內(nèi)存使用量除以 1024 的余數(shù)。
LUA_GCSTEP
:
發(fā)起一步增量垃圾收集。
LUA_GCSETPAUSE
:
把 data
設(shè)為 垃圾收集器間歇率
(參見 §2.5),并返回之前設(shè)置的值。
LUA_GCSETSTEPMUL
:
把 data
設(shè)為 垃圾收集器步進(jìn)倍率
(參見 §2.5),并返回之前設(shè)置的值。
LUA_GCISRUNNING
:
返回收集器是否在運行(即沒有停止)。
關(guān)于這些選項的細(xì)節(jié),參見 collectgarbage
。
lua_getallocf
[-0, +0, –]
lua_Alloc lua_getallocf (lua_State *L, void **ud);
返回給定狀態(tài)機的內(nèi)存分配器函數(shù)。
如果 ud
不是 NULL
,
Lua 把設(shè)置內(nèi)存分配函數(shù)時設(shè)置的那個指針置入 *ud
。
lua_getfield
[-0, +1, e]
int lua_getfield (lua_State *L, int index, const char *k);
把 t[k]
的值壓棧,
這里的 t
是索引指向的值。
在 Lua 中,這個函數(shù)可能觸發(fā)對應(yīng) "index" 事件對應(yīng)的元方法
(參見 §2.4 )。
函數(shù)將返回壓入值的類型。
lua_getextraspace
[-0, +0, –]
void *lua_getextraspace (lua_State *L);
返回一個 Lua 狀態(tài)機中關(guān)聯(lián)的內(nèi)存塊指針。 程序可以把這塊內(nèi)存用于任何用途;而 Lua 不會使用它。
每一個新線程都會攜帶一塊內(nèi)存, 初始化為主線程的這塊內(nèi)存的副本。
默認(rèn)配置下,這塊內(nèi)存的大小為空指針的大小。
不過你可以重新編譯 Lua 設(shè)定這塊內(nèi)存不同的大小。
(參見 luaconf.h
中的 LUA_EXTRASPACE
。)
lua_getglobal
[-0, +1, e]
int lua_getglobal (lua_State *L, const char *name);
把全局變量
lua_geti
[-0, +1, e]
int lua_geti (lua_State *L, int index, lua_Integer i);
把 t[i]
的值壓棧,
這里的 t
指給定的索引指代的值。
和在 Lua 里一樣,這個函數(shù)可能會觸發(fā) "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
則是棧頂放的值。
這個函數(shù)會彈出堆棧上的鍵,把結(jié)果放在棧上相同位置。 和在 Lua 中一樣, 這個函數(shù)可能觸發(fā)對應(yīng) "index" 事件的元方法 (參見 §2.4 )。
返回壓入值的類型。
lua_gettop
[-0, +0, –]
int lua_gettop (lua_State *L);
返回棧頂元素的索引。 因為索引是從 1 開始編號的, 所以這個結(jié)果等于棧上的元素個數(shù); 特別指出,0 表示棧為空。
lua_getuservalue
[-0, +1, –]
int lua_getuservalue (lua_State *L, int index);
將給定索引處的用戶數(shù)據(jù)所關(guān)聯(lián)的 Lua 值壓棧。
返回壓入值的類型。
lua_insert
[-1, +1, –]
void lua_insert (lua_State *L, int index);
把棧頂元素移動到指定的有效索引處, 依次移動這個索引之上的元素。 不要用偽索引來調(diào)用這個函數(shù), 因為偽索引沒有真正指向棧上的位置。
lua_Integer
typedef ... lua_Integer;
Lua 中的整數(shù)類型。
缺省時,這個就是 long long
,
(通常是一個 64 位以二為補碼的整數(shù)),
也可以修改它為 long
或 int
(通常是一個 32 位以二為補碼的整數(shù))。
(參見 luaconf.h
中的 LUA_INT
。)
Lua 定義了兩個常量:
LUA_MININTEGER
和
LUA_MAXINTEGER
來表示這個類型可以表示的最小和最大值。
lua_isboolean
[-0, +0, –]
int lua_isboolean (lua_State *L, int index);
當(dāng)給定索引的值是一個布爾量時,返回 1 ,否則返回 0 。
lua_iscfunction
[-0, +0, –]
int lua_iscfunction (lua_State *L, int index);
當(dāng)給定索引的值是一個 C 函數(shù)時,返回 1 ,否則返回 0 。
lua_isfunction
[-0, +0, –]
int lua_isfunction (lua_State *L, int index);
當(dāng)給定索引的值是一個函數(shù)( C 或 Lua 函數(shù)均可)時,返回 1 ,否則返回 0 。
lua_isinteger
[-0, +0, –]
int lua_isinteger (lua_State *L, int index);
當(dāng)給定索引的值是一個整數(shù) (其值是一個數(shù)字,且內(nèi)部以整數(shù)儲存), 時,返回 1 ,否則返回 0 。
lua_islightuserdata
[-0, +0, –]
int lua_islightuserdata (lua_State *L, int index);
當(dāng)給定索引的值是一個輕量用戶數(shù)據(jù)時,返回 1 ,否則返回 0 。
lua_isnil
[-0, +0, –]
int lua_isnil (lua_State *L, int index);
當(dāng)給定索引的值是 nil 時,返回 1 ,否則返回 0 。
lua_isnone
[-0, +0, –]
int lua_isnone (lua_State *L, int index);
當(dāng)給定索引無效時,返回 1 ,否則返回 0 。
lua_isnoneornil
[-0, +0, –]
int lua_isnoneornil (lua_State *L, int index);
當(dāng)給定索引無效或其值是 nil 時, 返回 1 ,否則返回 0 。
lua_isnumber
[-0, +0, –]
int lua_isnumber (lua_State *L, int index);
當(dāng)給定索引的值是一個數(shù)字,或是一個可轉(zhuǎn)換為數(shù)字的字符串時,返回 1 ,否則返回 0 。
lua_isstring
[-0, +0, –]
int lua_isstring (lua_State *L, int index);
當(dāng)給定索引的值是一個字符串或是一個數(shù)字 (數(shù)字總能轉(zhuǎn)換成字符串)時,返回 1 ,否則返回 0 。
lua_istable
[-0, +0, –]
int lua_istable (lua_State *L, int index);
當(dāng)給定索引的值是一張表時,返回 1 ,否則返回 0 。
lua_isthread
[-0, +0, –]
int lua_isthread (lua_State *L, int index);
當(dāng)給定索引的值是一條線程時,返回 1 ,否則返回 0 。
lua_isuserdata
[-0, +0, –]
int lua_isuserdata (lua_State *L, int index);
當(dāng)給定索引的值是一個用戶數(shù)據(jù)(無論是完全的還是輕量的)時, 返回 1 ,否則返回 0 。
lua_isyieldable
[-0, +0, –]
int lua_isyieldable (lua_State *L);
如果給定的協(xié)程可以讓出,返回 1 ,否則返回 0 。
lua_KContext
typedef ... lua_KContext;
延續(xù)函數(shù)上下文參數(shù)的類型。
這一定是一個數(shù)字類型。
當(dāng)有 intptr_t
時,被定義為 intptr_t
,
因此它也可以保存指針。
否則,它被定義為 ptrdiff_t
。
lua_KFunction
typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);
延續(xù)函數(shù)的類型(參見 §4.7 )。
lua_len
[-0, +1, e]
void lua_len (lua_State *L, int index);
返回給定索引的值的長度。
它等價于 Lua 中的 '#
' 操作符
(參見 §3.4.7)。
它有可能觸發(fā) "length" 事件對應(yīng)的元方法
(參見 §2.4 )。
結(jié)果壓棧。
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 函數(shù)壓到棧頂。
否則,壓入錯誤消息。
lua_load
的返回值可以是:
LUA_OK
: 沒有錯誤;LUA_ERRSYNTAX
:
在預(yù)編譯時碰到語法錯誤;LUA_ERRMEM
:
內(nèi)存分配錯誤;LUA_ERRGCMM
:
在運行 __gc
元方法時出錯了。
(這個錯誤和代碼塊加載過程無關(guān),它是由垃圾收集器引發(fā)的。)
lua_load
函數(shù)使用一個用戶提供的 reader
函數(shù)來讀取代碼塊(參見 lua_Reader
)。
data
參數(shù)會被傳入 reader
函數(shù)。
chunkname
這個參數(shù)可以賦予代碼塊一個名字,
這個名字被用于出錯信息和調(diào)試信息(參見 §4.9)。
lua_load
會自動檢測代碼塊是文本的還是二進(jìn)制的,
然后做對應(yīng)的加載操作(參見程序 luac
)。
字符串 mode
的作用和函數(shù) load
一致。
它還可以是 NULL
等價于字符串 "bt
"。
lua_load
的內(nèi)部會使用棧,
因此 reader 函數(shù)必須永遠(yuǎn)在每次返回時保留棧的原樣。
如果返回的函數(shù)有上值,
第一個上值會被設(shè)置為
保存在注冊表(參見 §4.5)
LUA_RIDX_GLOBALS
索引處的全局環(huán)境。
在加載主代碼塊時,這個上值是 _ENV
變量(參見 §2.2)。
其它上值均被初始化為 nil。
lua_newstate
[-0, +0, –]
lua_State *lua_newstate (lua_Alloc f, void *ud);
創(chuàng)建一個運行在新的獨立的狀態(tài)機中的線程。
如果無法創(chuàng)建線程或狀態(tài)機(由于內(nèi)存有限)則返回 NULL
。
參數(shù) f
是一個分配器函數(shù);
Lua 將通過這個函數(shù)做狀態(tài)機內(nèi)所有的內(nèi)存分配操作。
第二個參數(shù) ud
,這個指針將在每次調(diào)用分配器時被轉(zhuǎn)入。
lua_newtable
[-0, +1, e]
void lua_newtable (lua_State *L);
創(chuàng)建一張空表,并將其壓棧。
它等價于 lua_createtable(L, 0, 0)
。
lua_newthread
[-0, +1, e]
lua_State *lua_newthread (lua_State *L);
創(chuàng)建一條新線程,并將其壓棧,
并返回維護(hù)這個線程的 lua_State
指針。
這個函數(shù)返回的新線程共享原線程的全局環(huán)境, 但是它有獨立的運行棧。
沒有顯式的函數(shù)可以用來關(guān)閉或銷毀掉一個線程。 線程跟其它 Lua 對象一樣是垃圾收集的條目之一。
lua_newuserdata
[-0, +1, e]
void *lua_newuserdata (lua_State *L, size_t size);
這個函數(shù)分配一塊指定大小的內(nèi)存塊, 把內(nèi)存塊地址作為一個完全用戶數(shù)據(jù)壓棧, 并返回這個地址。 宿主程序可以隨意使用這塊內(nèi)存。
lua_next
[-1, +(2|0), e]
int lua_next (lua_State *L, int index);
從棧頂彈出一個鍵,
然后把索引指定的表中的一個鍵值對壓棧 (彈出的鍵之后的 “下一” 對)。
如果表中以無更多元素,
那么 lua_next
將返回 0 (什么也不壓棧)。
典型的遍歷方法是這樣的:
/* 表放在索引 't' 處 */ lua_pushnil(L); /* 第一個鍵 */ while (lua_next(L, t) != 0) { /* 使用 '鍵' (在索引 -2 處) 和 '值' (在索引 -1 處)*/ printf("%s - %s\n", lua_typename(L, lua_type(L, -2)), lua_typename(L, lua_type(L, -1))); /* 移除 '值' ;保留 '鍵' 做下一次迭代 */ lua_pop(L, 1); }
在遍歷一張表的時候,
不要直接對鍵調(diào)用 lua_tolstring
,
除非你知道這個鍵一定是一個字符串。
調(diào)用 lua_tolstring
有可能改變給定索引位置的值;
這會對下一次調(diào)用 lua_next
造成影響。
關(guān)于迭代過程中修改被迭代的表的注意事項參見 next
函數(shù)。
lua_Number
typedef double lua_Number;
Lua 中浮點數(shù)的類型。
Lua 中數(shù)字的類型。缺省是 double ,但是你可以改成 float 。
(參見 luaconf.h
中的 LUA_REAL
。)
lua_numbertointeger
int lua_numbertointeger (lua_Number n, lua_Integer *p);
將一個 Lua 浮點數(shù)轉(zhuǎn)換為一個 Lua 整數(shù)。
這個宏假設(shè) n
有對應(yīng)的整數(shù)值。
如果該值在 Lua 整數(shù)可表示范圍內(nèi),
就將其轉(zhuǎn)換為一個整數(shù)賦給 *p
。
宏的結(jié)果是一個布爾量,表示轉(zhuǎn)換是否成功。
(注意、由于圓整關(guān)系,這個范圍測試不用此宏很難做對。)
該宏有可能對其參數(shù)做多次取值。
lua_pcall
[-(nargs + 1), +(nresults|1), –]
int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);
以保護(hù)模式調(diào)用一個函數(shù)。
nargs
和 nresults
的含義與 lua_call
中的相同。
如果在調(diào)用過程中沒有發(fā)生錯誤,
lua_pcall
的行為和 lua_call
完全一致。
但是,如果有錯誤發(fā)生的話,
lua_pcall
會捕獲它,
然后把唯一的值(錯誤消息)壓棧,然后返回錯誤碼。
同 lua_call
一樣,
lua_pcall
總是把函數(shù)本身和它的參數(shù)從棧上移除。
如果 msgh
是 0 ,
返回在棧頂?shù)腻e誤消息就和原始錯誤消息完全一致。
否則, msgh
就被當(dāng)成是 錯誤處理函數(shù) 在棧上的索引位置。
(在當(dāng)前的實現(xiàn)里,這個索引不能是偽索引。)
在發(fā)生運行時錯誤時,
這個函數(shù)會被調(diào)用而參數(shù)就是錯誤消息。
錯誤處理函數(shù)的返回值將被 lua_pcall
作為錯誤消息返回在堆棧上。
典型的用法中,錯誤處理函數(shù)被用來給錯誤消息加上更多的調(diào)試信息,
比如棧跟蹤信息。
這些信息在 lua_pcall
返回后,
由于棧已經(jīng)展開,所以收集不到了。
lua_pcall
函數(shù)會返回下列常數(shù)
(定義在 lua.h
內(nèi))中的一個:
LUA_OK
(0):
成功。LUA_ERRRUN
:
運行時錯誤。
LUA_ERRMEM
:
內(nèi)存分配錯誤。對于這種錯,Lua 不會調(diào)用錯誤處理函數(shù)。
LUA_ERRERR
:
在運行錯誤處理函數(shù)時發(fā)生的錯誤。
LUA_ERRGCMM
:
在運行 __gc
元方法時發(fā)生的錯誤。
(這個錯誤和被調(diào)用的函數(shù)無關(guān)。)
lua_pcallk
[-(nargs + 1), +(nresults|1), –]
int lua_pcallk (lua_State *L, int nargs, int nresults, int msgh, lua_KContext ctx, lua_KFunction k);
這個函數(shù)的行為和 lua_pcall
完全一致,只不過它還允許被調(diào)用的函數(shù)讓出
(參見 §4.7)。
lua_pop
[-n, +0, –]
void lua_pop (lua_State *L, int n);
從棧中彈出 n
個元素。
lua_pushboolean
[-0, +1, –]
void lua_pushboolean (lua_State *L, int b);
把 b
作為一個布爾量壓棧。
lua_pushcclosure
[-n, +1, e]
void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
把一個新的 C 閉包壓棧。
當(dāng)創(chuàng)建了一個 C 函數(shù)后,
你可以給它關(guān)聯(lián)一些值,
這就是在創(chuàng)建一個 C 閉包(參見 §4.4);
接下來無論函數(shù)何時被調(diào)用,這些值都可以被這個函數(shù)訪問到。
為了將一些值關(guān)聯(lián)到一個 C 函數(shù)上,
首先這些值需要先被壓入堆棧(如果有多個值,第一個先壓)。
接下來調(diào)用 lua_pushcclosure
來創(chuàng)建出閉包并把這個 C 函數(shù)壓到棧上。
參數(shù) n
告之函數(shù)有多少個值需要關(guān)聯(lián)到函數(shù)上。
lua_pushcclosure
也會把這些值從棧上彈出。
n
的最大值是 255 。
當(dāng) n
為零時,
這個函數(shù)將創(chuàng)建出一個 輕量 C 函數(shù),
它就是一個指向 C 函數(shù)的指針。
這種情況下,不可能拋出內(nèi)存錯誤。
lua_pushcfunction
[-0, +1, –]
void lua_pushcfunction (lua_State *L, lua_CFunction f);
將一個 C 函數(shù)壓棧。
這個函數(shù)接收一個 C 函數(shù)指針,
并將一個類型為 function
的 Lua 值壓棧。
當(dāng)這個棧頂?shù)闹当徽{(diào)用時,將觸發(fā)對應(yīng)的 C 函數(shù)。
注冊到 Lua 中的任何函數(shù)都必須遵循正確的協(xié)議來接收參數(shù)和返回值
(參見 lua_CFunction
)。
lua_pushcfunction
是作為一個宏定義出現(xiàn)的:
#define lua_pushcfunction(L,f) lua_pushcclosure(L,f,0)
lua_pushfstring
[-0, +1, e]
const char *lua_pushfstring (lua_State *L, const char *fmt, ...);
把一個格式化過的字符串壓棧,
然后返回這個字符串的指針。
它和 C 函數(shù) sprintf
比較像,
不過有一些重要的區(qū)別:
%%
' (插入一個字符 '%
'),
'%s
' (插入一個帶零終止符的字符串,沒有長度限制),
'%f
' (插入一個 lua_Number
),
'%I
' (插入一個 lua_Integer
),
'%p
' (插入一個指針或是一個十六進(jìn)制數(shù)),
'%d
' (插入一個 int
),
'%c
' (插入一個用 int
表示的單字節(jié)字符),以及
'%U
' (插入一個用 long int
表示的 UTF-8 字)。
lua_pushglobaltable
[-0, +1, –]
void lua_pushglobaltable (lua_State *L);
將全局環(huán)境壓棧。
lua_pushinteger
[-0, +1, –]
void lua_pushinteger (lua_State *L, lua_Integer n);
把值為 n
的整數(shù)壓棧。
lua_pushlightuserdata
[-0, +1, –]
void lua_pushlightuserdata (lua_State *L, void *p);
把一個輕量用戶數(shù)據(jù)壓棧。
用戶數(shù)據(jù)是保留在 Lua 中的 C 值。
輕量用戶數(shù)據(jù) 表示一個指針 void*
。
它是一個像數(shù)字一樣的值:
你不需要專門創(chuàng)建它,它也沒有獨立的元表,而且也不會被收集(因為從來不需要創(chuàng)建)。
只要表示的 C 地址相同,兩個輕量用戶數(shù)據(jù)就相等。
lua_pushliteral
[-0, +1, e]
const char *lua_pushliteral (lua_State *L, const char *s);
這個宏等價于 lua_pushstring
,
區(qū)別僅在于只能在 s
是一個字面量時才能用它。
它會自動給出字符串的長度。
lua_pushlstring
[-0, +1, e]
const char *lua_pushlstring (lua_State *L, const char *s, size_t len);
把指針 s
指向的長度為 len
的字符串壓棧。
Lua 對這個字符串做一個內(nèi)部副本(或是復(fù)用一個副本),
因此 s
處的內(nèi)存在函數(shù)返回后,可以釋放掉或是立刻重用于其它用途。
字符串內(nèi)可以是任意二進(jìn)制數(shù)據(jù),包括零字符。
返回內(nèi)部副本的指針。
lua_pushnil
[-0, +1, –]
void lua_pushnil (lua_State *L);
將空值壓棧。
lua_pushnumber
[-0, +1, –]
void lua_pushnumber (lua_State *L, lua_Number n);
把一個值為 n
的浮點數(shù)壓棧。
lua_pushstring
[-0, +1, e]
const char *lua_pushstring (lua_State *L, const char *s);
將指針 s 指向的零結(jié)尾的字符串壓棧。Lua 對這個字符串做一個內(nèi)部副本(或是復(fù)用一個副本),
因此 s
處的內(nèi)存在函數(shù)返回后,可以釋放掉或是立刻重用于其它用途。
返回內(nèi)部副本的指針。
如果 s
為 NULL
,將 nil 壓棧并返回 NULL
。
lua_pushthread
[-0, +1, –]
int lua_pushthread (lua_State *L);
把 L
表示的線程壓棧。
如果這個線程是當(dāng)前狀態(tài)機的主線程的話,返回 1 。
lua_pushvalue
[-0, +1, –]
void lua_pushvalue (lua_State *L, int index);
把棧上給定索引處的元素作一個副本壓棧。
lua_pushvfstring
[-0, +1, e]
const char *lua_pushvfstring (lua_State *L, const char *fmt, va_list argp);
等價于 lua_pushfstring
,
不過是用 va_list
接收參數(shù),而不是用可變數(shù)量的實際參數(shù)。
lua_rawequal
[-0, +0, –]
int lua_rawequal (lua_State *L, int index1, int index2);
如果索引 index1
與索引 index2
處的值
本身相等(即不調(diào)用元方法),返回 1 。
否則返回 0 。
當(dāng)任何一個索引無效時,也返回 0 。
lua_rawget
[-1, +1, –]
int lua_rawget (lua_State *L, int index);
類似于 lua_gettable
,
但是作一次直接訪問(不觸發(fā)元方法)。
lua_rawgeti
[-0, +1, –]
int lua_rawgeti (lua_State *L, int index, lua_Integer n);
把 t[n]
的值壓棧,
這里的 t
是指給定索引處的表。
這是一次直接訪問;就是說,它不會觸發(fā)元方法。
返回入棧值的類型。
lua_rawgetp
[-0, +1, –]
int lua_rawgetp (lua_State *L, int index, const void *p);
把 t[k]
的值壓棧,
這里的 t
是指給定索引處的表,
k
是指針 p
對應(yīng)的輕量用戶數(shù)據(jù)。
這是一次直接訪問;就是說,它不會觸發(fā)元方法。
返回入棧值的類型。
lua_rawlen
[-0, +0, –]
size_t lua_rawlen (lua_State *L, int index);
返回給定索引處值的固有“長度”:
對于字符串,它指字符串的長度;
對于表;它指不觸發(fā)元方法的情況下取長度操作('#
')應(yīng)得到的值;
對于用戶數(shù)據(jù),它指為該用戶數(shù)據(jù)分配的內(nèi)存塊的大??;
對于其它值,它為 0 。
lua_rawset
[-2, +0, e]
void lua_rawset (lua_State *L, int index);
類似于 lua_settable
,
但是是做一次直接賦值(不觸發(fā)元方法)。
lua_rawseti
[-1, +0, e]
void lua_rawseti (lua_State *L, int index, lua_Integer i);
等價于 t[i] = v
,
這里的 t
是指給定索引處的表,
而 v
是棧頂?shù)闹怠?
這個函數(shù)會將值彈出棧。 賦值是直接的;即不會觸發(fā)元方法。
lua_rawsetp
[-1, +0, e]
void lua_rawsetp (lua_State *L, int index, const void *p);
等價于 t[k] = v
,
這里的 t
是指給定索引處的表,
k
是指針 p
對應(yīng)的輕量用戶數(shù)據(jù)。
而 v
是棧頂?shù)闹怠?
這個函數(shù)會將值彈出棧。 賦值是直接的;即不會觸發(fā)元方法。
lua_Reader
typedef const char * (*lua_Reader) (lua_State *L, void *data, size_t *size);
lua_load
用到的讀取器函數(shù),
每次它需要一塊新的代碼塊的時候,
lua_load
就調(diào)用讀取器,
每次都會傳入一個參數(shù) data
。
讀取器需要返回含有新的代碼塊的一塊內(nèi)存的指針,
并把 size
設(shè)為這塊內(nèi)存的大小。
內(nèi)存塊必須在下一次函數(shù)被調(diào)用之前一直存在。
讀取器可以通過返回 NULL
或設(shè) size
為 0 來指示代碼塊結(jié)束。
讀取器可能返回多個塊,每個塊可以有任意的大于零的尺寸。
lua_register
[-0, +0, e]
void lua_register (lua_State *L, const char *name, lua_CFunction f);
把 C 函數(shù) f
設(shè)到全局變量 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);
從給定有效索引處移除一個元素, 把這個索引之上的所有元素移下來填補上這個空隙。 不能用偽索引來調(diào)用這個函數(shù),因為偽索引并不指向真實的棧上的位置。
lua_replace
[-1, +0, –]
void lua_replace (lua_State *L, int index);
把棧頂元素放置到給定位置而不移動其它元素 (因此覆蓋了那個位置處的值),然后將棧頂元素彈出。
lua_resume
[-?, +?, –]
int lua_resume (lua_State *L, lua_State *from, int nargs);
在給定線程中啟動或延續(xù)一條協(xié)程 。
要啟動一個協(xié)程的話,
你需要把主函數(shù)以及它需要的參數(shù)壓入線程棧;
然后調(diào)用 lua_resume
,
把 nargs
設(shè)為參數(shù)的個數(shù)。
這次調(diào)用會在協(xié)程掛起時或是結(jié)束運行后返回。
當(dāng)函數(shù)返回時,堆棧中會有傳給 lua_yield
的所有值,
或是主函數(shù)的所有返回值。
當(dāng)協(xié)程讓出, lua_resume
返回 LUA_YIELD
,
若協(xié)程結(jié)束運行且沒有任何錯誤時,返回 0 。
如果有錯則返回錯誤代碼(參見 lua_pcall
)。
在發(fā)生錯誤的情況下, 堆棧沒有展開, 因此你可以使用調(diào)試 API 來處理它。 錯誤消息放在棧頂。
要延續(xù)一個協(xié)程,
你需要清除上次 lua_yield
遺留下的所有結(jié)果,
你把需要傳給 yield
作結(jié)果的值壓棧,
然后調(diào)用 lua_resume
。
參數(shù) from
表示協(xié)程從哪個協(xié)程中來延續(xù) L
的。
如果不存在這樣一個協(xié)程,這個參數(shù)可以是 NULL
。
lua_rotate
[-0, +0, –]
void lua_rotate (lua_State *L, int idx, int n);
把從 idx
開始到棧頂?shù)脑剌嗈D(zhuǎn) n
個位置。
對于 n
為正數(shù)時,輪轉(zhuǎn)方向是向棧頂?shù)模?當(dāng) n
為負(fù)數(shù)時,向棧底方向輪轉(zhuǎn) -n
個位置。
n
的絕對值不可以比參于輪轉(zhuǎn)的切片長度大。
lua_setallocf
[-0, +0, –]
void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);
把指定狀態(tài)機的分配器函數(shù)換成帶上用戶數(shù)據(jù) ud
的 f
。
lua_setfield
[-1, +0, e]
void lua_setfield (lua_State *L, int index, const char *k);
做一個等價于 t[k] = v
的操作,
這里 t
是給出的索引處的值,
而 v
是棧頂?shù)哪莻€值。
這個函數(shù)將把這個值彈出棧。 跟在 Lua 中一樣,這個函數(shù)可能觸發(fā)一個 "newindex" 事件的元方法 (參見 §2.4)。
lua_setglobal
[-1, +0, e]
void lua_setglobal (lua_State *L, const char *name);
從堆棧上彈出一個值,并將其設(shè)為全局變量 name
的新值。
lua_seti
[-1, +0, e]
void lua_seti (lua_State *L, int index, lua_Integer n);
做一個等價于 t[n] = v
的操作,
這里 t
是給出的索引處的值,
而 v
是棧頂?shù)哪莻€值。
這個函數(shù)將把這個值彈出棧。 跟在 Lua 中一樣,這個函數(shù)可能觸發(fā)一個 "newindex" 事件的元方法 (參見 §2.4)。
lua_setmetatable
[-1, +0, –]
void lua_setmetatable (lua_State *L, int index);
把一張表彈出棧,并將其設(shè)為給定索引處的值的元表。
lua_settable
[-2, +0, e]
void lua_settable (lua_State *L, int index);
做一個等價于 t[k] = v
的操作,
這里 t
是給出的索引處的值,
v
是棧頂?shù)哪莻€值,
k
是棧頂之下的值。
這個函數(shù)會將鍵和值都彈出棧。 跟在 Lua 中一樣,這個函數(shù)可能觸發(fā)一個 "newindex" 事件的元方法 (參見 §2.4)。
lua_settop
[-?, +?, –]
void lua_settop (lua_State *L, int index);
參數(shù)允許傳入任何索引以及 0 。
它將把堆棧的棧頂設(shè)為這個索引。
如果新的棧頂比原來的大,
超出部分的新元素將被填為 nil 。
如果 index
為 0 ,
把棧上所有元素移除。
lua_setuservalue
[-1, +0, –]
void lua_setuservalue (lua_State *L, int index);
從棧上彈出一個值并將其設(shè)為給定索引處用戶數(shù)據(jù)的關(guān)聯(lián)值。
lua_State
typedef struct lua_State lua_State;
一個不透明的結(jié)構(gòu), 它指向一條線程并間接(通過該線程)引用了整個 Lua 解釋器的狀態(tài)。 Lua 庫是完全可重入的: 它沒有任何全局變量。 狀態(tài)機所有的信息都可以通過這個結(jié)構(gòu)訪問到。
這個結(jié)構(gòu)的指針必須作為第一個參數(shù)傳遞給每一個庫函數(shù)。
lua_newstate
是一個例外,
這個函數(shù)會從頭創(chuàng)建一個 Lua 狀態(tài)機。
lua_status
[-0, +0, –]
int lua_status (lua_State *L);
返回線程 L
的狀態(tài)。
正常的線程狀態(tài)是 0 (LUA_OK
)。
當(dāng)線程用 lua_resume
執(zhí)行完畢并拋出了一個錯誤時,
狀態(tài)值是錯誤碼。
如果線程被掛起,狀態(tài)為 LUA_YIELD
。
你只能在狀態(tài)為 LUA_OK
的線程中調(diào)用函數(shù)。
你可以延續(xù)一個狀態(tài)為 LUA_OK
的線程
(用于開始新協(xié)程)或是狀態(tài)為 LUA_YIELD
的線程
(用于延續(xù)協(xié)程)。
lua_stringtonumber
[-0, +1, –]
size_t lua_stringtonumber (lua_State *L, const char *s);
將一個零結(jié)尾的字符串 s
轉(zhuǎn)換為一個數(shù)字,
將這個數(shù)字壓棧,并返回字符串的總長度(即長度加一)。
轉(zhuǎn)換的結(jié)果可能是整數(shù)也可能是浮點數(shù),
這取決于 Lua 的轉(zhuǎn)換語法(參見 §3.1)。
這個字符串可以有前置和后置的空格以及符號。
如果字符串并非一個有效的數(shù)字,返回 0 并不把任何東西壓棧。
(注意,這個結(jié)果可以當(dāng)成一個布爾量使用,為真即轉(zhuǎn)換成功。)
lua_toboolean
[-0, +0, –]
int lua_toboolean (lua_State *L, int index);
把給定索引處的 Lua 值轉(zhuǎn)換為一個 C 中的布爾量( 0 或是 1 )。
和 Lua 中做的所有測試一樣,
lua_toboolean
會把任何不同于 false 和 nil 的值當(dāng)作真返回;
否則就返回假。
(如果你想只接收真正的 boolean 值,
就需要使用 lua_isboolean
來測試值的類型。)
lua_tocfunction
[-0, +0, –]
lua_CFunction lua_tocfunction (lua_State *L, int index);
把給定索引處的 Lua 值轉(zhuǎn)換為一個 C 函數(shù)。
這個值必須是一個 C 函數(shù);
如果不是就返回 NULL
。
lua_tointeger
[-0, +0, –]
lua_Integer lua_tointeger (lua_State *L, int index);
等價于調(diào)用 lua_tointegerx
,
其參數(shù) isnum
為 NULL
。
lua_tointegerx
[-0, +0, –]
lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);
將給定索引處的 Lua 值轉(zhuǎn)換為帶符號的整數(shù)類型
lua_Integer
。
這個 Lua 值必須是一個整數(shù),或是一個可以被轉(zhuǎn)換為整數(shù)
(參見 §3.4.3)的數(shù)字或字符串;
否則,lua_tointegerx
返回 0 。
如果 isnum
不是 NULL
,
*isnum
會被設(shè)為操作是否成功。
lua_tolstring
[-0, +0, e]
const char *lua_tolstring (lua_State *L, int index, size_t *len);
把給定索引處的 Lua 值轉(zhuǎn)換為一個 C 字符串。
如果 len
不為 NULL
,
它還把字符串長度設(shè)到 *len
中。
這個 Lua 值必須是一個字符串或是一個數(shù)字;
否則返回 NULL
。
如果值是一個數(shù)字, lua_tolstring
還會 把堆棧中的那個值的實際類型轉(zhuǎn)換為一個字符串。
(當(dāng)遍歷一張表的時候,
若把 lua_tolstring
作用在鍵上,
這個轉(zhuǎn)換有可能導(dǎo)致 lua_next
弄錯。)
lua_tolstring
返回一個已對齊指針
指向 Lua 狀態(tài)機中的字符串。
這個字符串總能保證 ( C 要求的)最后一個字符為零 ('\0') ,
而且它允許在字符串內(nèi)包含多個這樣的零。
因為 Lua 中可能發(fā)生垃圾收集,
所以不保證 lua_tolstring
返回的指針,
在對應(yīng)的值從堆棧中移除后依然有效。
lua_tonumber
[-0, +0, –]
lua_Number lua_tonumber (lua_State *L, int index);
等價于調(diào)用 lua_tonumberx
,
其參數(shù) isnum
為 NULL
。
lua_tonumberx
[-0, +0, –]
lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);
把給定索引處的 Lua 值轉(zhuǎn)換為 lua_Number
這樣一個 C 類型
(參見 lua_Number )。
這個 Lua 值必須是一個數(shù)字或是一個可轉(zhuǎn)換為數(shù)字的字符串
(參見 §3.4.3);
否則, lua_tonumberx
返回 0 。
如果 isnum
不是 NULL
,
*isnum
會被設(shè)為操作是否成功。
lua_topointer
[-0, +0, –]
const void *lua_topointer (lua_State *L, int index);
把給定索引處的值轉(zhuǎn)換為一般的 C 指針 (void*
) 。
這個值可以是一個用戶對象,表 ,線程或是一個函數(shù);
否則, lua_topointer
返回 NULL
。
不同的對象有不同的指針。
不存在把指針再轉(zhuǎn)回原有類型的方法。
這個函數(shù)通常只用于調(diào)試信息。
lua_tostring
[-0, +0, e]
const char *lua_tostring (lua_State *L, int index);
等價于調(diào)用 lua_tolstring
,
其參數(shù) len
為 NULL
。
lua_tothread
[-0, +0, –]
lua_State *lua_tothread (lua_State *L, int index);
把給定索引處的值轉(zhuǎn)換為一個 Lua 線程
(表示為 lua_State*
)。
這個值必須是一個線程;
否則函數(shù)返回 NULL
。
lua_touserdata
[-0, +0, –]
void *lua_touserdata (lua_State *L, int index);
如果給定索引處的值是一個完全用戶數(shù)據(jù),
函數(shù)返回其內(nèi)存塊的地址。
如果值是一個輕量用戶數(shù)據(jù),
那么就返回它表示的指針。
否則,返回 NULL
。
lua_type
[-0, +0, –]
int lua_type (lua_State *L, int index);
返回給定有效索引處值的類型,
當(dāng)索引無效(或無法訪問)時則返回 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
表示的類型名,
這個 tp
必須是 lua_type
可能返回的值中之一。
lua_Unsigned
typedef ... lua_Unsigned;
lua_Integer
的無符號版本。
lua_upvalueindex
[-0, +0, –]
int lua_upvalueindex (int i);
返回當(dāng)前運行的函數(shù)(參見 §4.4)的第 i
個上值的偽索引。
lua_version
[-0, +0, v]
const lua_Number *lua_version (lua_State *L);
返回保存在 Lua 內(nèi)核中儲存的版本數(shù)字的地址。
當(dāng)調(diào)用時傳入一個合法的 lua_State
,
返回創(chuàng)建該狀態(tài)機時的版本地址。
如果用 NULL
調(diào)用,
返回調(diào)用者的版本地址。
lua_Writer
typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud);
被 lua_dump
用到的寫入器函數(shù)。
每次 lua_dump
產(chǎn)生了一段新的代碼塊,
它都會調(diào)用寫入器。
傳入要寫入的緩沖區(qū) (p
) 和它的尺寸 (sz
) ,
以及傳給 lua_dump
的參數(shù) data
。
寫入器會返回一個錯誤碼:
0 表示沒有錯誤; 別的值均表示一個錯誤,
并且會讓 lua_dump
停止再次調(diào)用寫入器。
lua_xmove
[-?, +?, –]
void lua_xmove (lua_State *from, lua_State *to, int n);
交換同一個狀態(tài)機下不同線程中的值。
這個函數(shù)會從 from
的棧上彈出 n
個值,
然后把它們壓入 to
的棧上。
lua_yield
[-?, +?, e]
int lua_yield (lua_State *L, int nresults);
這個函數(shù)等價于調(diào)用 lua_yieldk
,
不同的是不提供延續(xù)函數(shù)(參見 §4.7)。
因此,當(dāng)線程被延續(xù),線程會繼續(xù)運行調(diào)用 lua_yield
函數(shù)的函數(shù)。
lua_yieldk
[-?, +?, e]
int lua_yieldk (lua_State *L, int nresults, lua_KContext ctx, lua_KFunction k);
讓出協(xié)程(線程)。
當(dāng) C 函數(shù)調(diào)用了 lua_yieldk
,
當(dāng)前運行的協(xié)程會掛起,
啟動這個線程的 lua_resume
調(diào)用返回。
參數(shù) nresults
指棧上需返回給
lua_resume
的返回值的個數(shù)。
當(dāng)協(xié)程再次被延續(xù)時,
Lua 調(diào)用延續(xù)函數(shù) k
繼續(xù)運行被掛起(參見 §4.7)的 C 函數(shù)。
延續(xù)函數(shù)會從前一個函數(shù)中接收到相同的棧,
棧中的 n
個返回值被移除而壓入了從
lua_resume
傳入的參數(shù)。
此外,延續(xù)函數(shù)還會收到傳給 lua_yieldk
的參數(shù) ctx
。
通常,這個函數(shù)不會返回;
當(dāng)協(xié)程一次次延續(xù),將從延續(xù)函數(shù)繼續(xù)運行。
然而,有一個例外:
當(dāng)這個函數(shù)從一個逐行運行的鉤子函數(shù)(參見 §4.9)
中調(diào)用時,lua_yieldk
不可以提供延續(xù)函數(shù)。
(也就是類似 lua_yield
的形式),
而此時,鉤子函數(shù)在調(diào)用完讓出后將立刻返回。
Lua 會使協(xié)程讓出,一旦協(xié)程再次被延續(xù),
觸發(fā)鉤子的函數(shù)會繼續(xù)正常運行。
當(dāng)一個線程處于未提供延續(xù)函數(shù)的 C 調(diào)用中,調(diào)用它會拋出一個錯誤。 從并非用延續(xù)方式(例如:主線程)啟動的線程中調(diào)用它也會這樣。
Lua 沒有內(nèi)置的調(diào)試機制。 但是它提供了一組特殊的函數(shù)接口以及 鉤子。 這組接口可用于構(gòu)建出不同的調(diào)試器、性能剖析器、 或是其它需要從解釋器獲取“內(nèi)部信息”的工具。
lua_Debug
typedef struct lua_Debug { int event; const char *name; /* (n) */ const char *namewhat; /* (n) */ const char *what; /* (S) */ const char *source; /* (S) */ int currentline; /* (l) */ int linedefined; /* (S) */ int lastlinedefined; /* (S) */ unsigned char nups; /* (u) 上值的數(shù)量 */ unsigned char nparams; /* (u) 參數(shù)的數(shù)量 */ char isvararg; /* (u) */ char istailcall; /* (t) */ char short_src[LUA_IDSIZE]; /* (S) */ /* 私有部分 */ 其它域 } lua_Debug;
這是一個攜帶有有關(guān)函數(shù)或活動記錄的各種信息的結(jié)構(gòu)。
lua_getstack
只會填充結(jié)構(gòu)的私有部分供后面使用。
調(diào)用 lua_getinfo
可以在
lua_Debug
中填充那些可被使用的信息域。
下面對 lua_Debug
的各個域做一個說明:
source
:
創(chuàng)建這個函數(shù)的代碼塊的名字。
如果 source
以 '@
' 打頭,
指這個函數(shù)定義在一個文件中,而 '@
' 之后的部分就是文件名。
若 source
以 '=
' 打頭,
剩余的部分由用戶行為來決定如何表示源碼。
其它的情況下,這個函數(shù)定義在一個字符串中,
而 source
正是那個字符串。
short_src
:
一個“可打印版本”的 source
,用于出錯信息。
linedefined
:
函數(shù)定義開始處的行號。
lastlinedefined
:
函數(shù)定義結(jié)束處的行號。
what
:
如果函數(shù)是一個 Lua 函數(shù),則為一個字符串 "Lua"
;
如果是一個 C 函數(shù),則為 "C"
;
如果它是一個代碼塊的主體部分,則為 "main"
。
currentline
:
給定函數(shù)正在執(zhí)行的那一行。
當(dāng)提供不了行號信息的時候, currentline
被設(shè)為 -1 。
name
:
給定函數(shù)的一個合理的名字。
因為 Lua 中的函數(shù)是一等公民,
所以它們沒有固定的名字:
一些函數(shù)可能是全局復(fù)合變量的值,
另一些可能僅僅只是被保存在一張表的某個域中。
lua_getinfo
函數(shù)會檢查函數(shù)是怎樣被調(diào)用的,
以此來找到一個適合的名字。
如果它找不到名字,
name
就被設(shè)置為 NULL
。
namewhat
:
用于解釋 name
域。
namewhat
的值可以是
"global"
, "local"
, "method"
, "field"
, "upvalue"
, 或是 ""
(空串)。
這取決于函數(shù)怎樣被調(diào)用。
(Lua 用空串表示其它選項都不符合。)
istailcall
:
如果函數(shù)以尾調(diào)用形式調(diào)用,這個值就為真。
在這種情況下,當(dāng)層的調(diào)用者不在棧中。
nups
:
函數(shù)的上值個數(shù)。
nparams
:
函數(shù)固定形參個數(shù)
(對于 C 函數(shù)永遠(yuǎn)是 0 )。
isvararg
:
如果函數(shù)是一個可變參數(shù)函數(shù)則為真
(對于 C 函數(shù)永遠(yuǎn)為真)。
lua_gethook
[-0, +0, –]
lua_Hook lua_gethook (lua_State *L);
返回當(dāng)前的鉤子函數(shù)。
lua_gethookcount
[-0, +0, –]
int lua_gethookcount (lua_State *L);
返回當(dāng)前的鉤子計數(shù)。
lua_gethookmask
[-0, +0, –]
int lua_gethookmask (lua_State *L);
返回當(dāng)前的鉤子掩碼。
lua_getinfo
[-(0|1), +(0|1|2), e]
int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
返回一個指定的函數(shù)或函數(shù)調(diào)用的信息。
當(dāng)用于取得一次函數(shù)調(diào)用的信息時,
參數(shù) ar
必須是一個有效的活動的記錄。
這條記錄可以是前一次調(diào)用 lua_getstack
得到的,
或是一個鉤子 (參見 lua_Hook
)得到的參數(shù)。
用于獲取一個函數(shù)的信息時,
可以把這個函數(shù)壓入堆棧,
然后把 what
字符串以字符 '>
' 起頭。
(這會讓 lua_getinfo
從棧頂上彈出函數(shù)。)
例如,想知道函數(shù) f
是在哪一行定義的,
你可以使用下列代碼:
lua_Debug ar; lua_getglobal(L, "f"); /* 取得全局變量 'f' */ lua_getinfo(L, ">S", &ar); printf("%d\n", ar.linedefined);
what
字符串中的每個字符都篩選出結(jié)構(gòu)
ar
結(jié)構(gòu)中一些域用于填充,
或是把一個值壓入堆棧:
n
': 填充 name
及 namewhat
域;
S
':
填充 source
, short_src
, linedefined
, lastlinedefined
,以及 what
域;
l
': 填充 currentline
域;
t
': 填充 istailcall
域;
u
': 填充 nups
, nparams
,及 isvararg
域;
f
':
把正在運行中指定層次處函數(shù)壓棧;
L
':
將一張表壓棧,這張表中的整數(shù)索引用于描述函數(shù)中哪些行是有效行。
(有效行指有實際代碼的行,即你可以置入斷點的行。 無效行包括空行和只有注釋的行。)
如果這個選項和選項 'f
' 同時使用,
這張表在函數(shù)之后壓棧。
這個函數(shù)出錯會返回 0 (例如,what
中有一個無效選項)。
lua_getlocal
[-0, +(0|1), –]
const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
從給定活動記錄或從一個函數(shù)中獲取一個局部變量的信息。
對于第一種情況,
參數(shù) ar
必須是一個有效的活動的記錄。
這條記錄可以是前一次調(diào)用 lua_getstack
得到的,
或是一個鉤子 (參見 lua_Hook
)的參數(shù)。
索引 n
用于選擇要檢閱哪個局部變量;
參見 debug.getlocal
中關(guān)于變量的索引和名字的介紹。
lua_getlocal
將變量的值壓棧,并返回其名字。
對于第二種情況,ar
必須填 NULL
。
需要探知的函數(shù)必須放在棧頂。
對于這種情況,只有 Lua 函數(shù)的形參是可見的
(沒有關(guān)于還有哪些活動變量的信息)
也不會有任何值壓棧。
當(dāng)索引大于活動的局部變量的數(shù)量,
返回 NULL
(無任何壓棧)
lua_getstack
[-0, +0, –]
int lua_getstack (lua_State *L, int level, lua_Debug *ar);
獲取解釋器的運行時棧的信息。
這個函數(shù)用正在運行中的指定層次處函數(shù)的 活動記錄 來填寫
lua_Debug
結(jié)構(gòu)的一部分。
0 層表示當(dāng)前運行的函數(shù),
n+1 層的函數(shù)就是調(diào)用第 n 層
(尾調(diào)用例外,它不算在棧層次中)
函數(shù)的那一個。
如果沒有錯誤, lua_getstack
返回 1 ;
當(dāng)調(diào)用傳入的層次大于堆棧深度的時候,返回 0 。
lua_getupvalue
[-0, +(0|1), –]
const char *lua_getupvalue (lua_State *L, int funcindex, int n);
獲取一個閉包的上值信息。
(對于 Lua 函數(shù),上值是函數(shù)需要使用的外部局部變量,
因此這些變量被包含在閉包中。)
lua_getupvalue
獲取第 n
個上值,
把這個上值的值壓棧,
并且返回它的名字。
funcindex
指向閉包在棧上的位置。
( 因為上值在整個函數(shù)中都有效,所以它們沒有特別的次序。
因此,它們以字母次序來編號。)
當(dāng)索引號比上值數(shù)量大的時候,
返回 NULL
(而且不會壓入任何東西)。
對于 C 函數(shù),所有上值的名字都是空串 ""
。
lua_Hook
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
用于調(diào)試的鉤子函數(shù)類型。
無論何時鉤子被調(diào)用,它的參數(shù) ar
中的 event
域都被設(shè)為觸發(fā)鉤子的事件。
Lua 把這些事件定義為以下常量:
LUA_HOOKCALL
,LUA_HOOKRET
,
LUA_HOOKTAILCALL
,LUA_HOOKLINE
,
LUA_HOOKCOUNT
。
除此之外,對于 line 事件, currentline
域也被設(shè)置。
要想獲得 ar
中的其他域,
鉤子必須調(diào)用 lua_getinfo
。
對于 call 事件,event
可以是 LUA_HOOKCALL
這個通常值,
或是 LUA_HOOKTAILCALL
表示尾調(diào)用;
后一種情況,沒有對應(yīng)的返回事件。
當(dāng) Lua 運行在一個鉤子內(nèi)部時, 它將屏蔽掉其它對鉤子的調(diào)用。 也就是說,如果一個鉤子函數(shù)內(nèi)再調(diào)回 Lua 來執(zhí)行一個函數(shù)或是一個代碼塊 , 這個執(zhí)行操作不會觸發(fā)任何的鉤子。
鉤子函數(shù)不能有延續(xù)點,
即不能用一個非空的 k
調(diào)用
lua_yieldk
,
lua_pcallk
,或 lua_callk
。
鉤子函數(shù)可以在滿足下列條件時讓出:
只有行計數(shù)事件可以讓出,且不能在讓出時傳出任何值;
從鉤子里讓出必須用 lua_yield
來結(jié)束鉤子的運行,且 nresults
必須為零。
lua_sethook
[-0, +0, –]
void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);
設(shè)置一個調(diào)試用鉤子函數(shù)。
參數(shù) f
是鉤子函數(shù)。
mask
指定在哪些事件時會調(diào)用:
它由下列一組位常量構(gòu)成
LUA_MASKCALL
,
LUA_MASKRET
,
LUA_MASKLINE
,
LUA_MASKCOUNT
。
參數(shù) count
只在掩碼中包含有 LUA_MASKCOUNT
才有意義。
對于每個事件,鉤子被調(diào)用的情況解釋如下:
count
條指令后被調(diào)用。
(這個事件僅僅在 Lua 執(zhí)行一個 Lua 函數(shù)時發(fā)生。)
鉤子可以通過設(shè)置 mask
為零屏蔽。
lua_setlocal
[-(0|1), +0, –]
const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
設(shè)置給定活動記錄中的局部變量的值。
參數(shù) ar
與 n
和
lua_getlocal
中的一樣
(參見 lua_getlocal
)。
lua_setlocal
把棧頂?shù)闹蒂x給變量然后返回變量的名字。
它會將值從棧頂彈出。
當(dāng)索引大于活動局部變量的數(shù)量時,返回 NULL
(什么也不彈出)。
lua_setupvalue
[-(0|1), +0, –]
const char *lua_setupvalue (lua_State *L, int funcindex, int n);
設(shè)置閉包上值的值。
它把棧頂?shù)闹祻棾霾①x于上值并返回上值的名字。
參數(shù) funcindex
與 n
和
lua_getupvalue
中的一樣
(參見 lua_getupvalue
)。
當(dāng)索引大于上值的數(shù)量時,返回 NULL
(什么也不彈出)。
lua_upvalueid
[-0, +0, –]
void *lua_upvalueid (lua_State *L, int funcindex, int n);
返回索引 funcindex
處的閉包中
編號為 n
的上值的一個唯一標(biāo)識符。
參數(shù) funcindex
與 n
和
lua_getupvalue
中的一樣
(參見 lua_getupvalue
)。
(但 n
不可以大于上值的數(shù)量)。
這些唯一標(biāo)識符可用于檢測不同的閉包是否共享了相同的上值。 共享同一個上值的 Lua 閉包(即它們指的同一個外部局部變量) 會針對這個上值返回相同的標(biāo)識。
lua_upvaluejoin
[-0, +0, –]
void lua_upvaluejoin (lua_State *L, int funcindex1, int n1, int funcindex2, int n2);
讓索引 funcindex1
處的 Lua 閉包的第 n1
個上值
引用索引 funcindex2
處的 Lua 閉包的第 n2
個上值。
輔助庫 提供了一些便捷函數(shù),方便在 C 中為 Lua 編程。 基礎(chǔ) API 提供了 C 和 Lua 交互用的主要函數(shù), 而輔助庫則為一些常見的任務(wù)提供了高階函數(shù)。
所有輔助庫中的函數(shù)和類型都定義在頭文件 lauxlib.h
中,
它們均帶有前綴 luaL_
。
輔助庫中的所有函數(shù)都基于基礎(chǔ) API 實現(xiàn)。 故而它們并沒有提供任何基礎(chǔ) API 實現(xiàn)不了的功能。 雖然如此,使用輔助庫可以讓你的代碼更為健壯。
一些輔助庫函數(shù)會在內(nèi)部使用一些額外的棧空間。 當(dāng)輔助庫使用的??臻g少于五個時, 它們不去檢查棧大小;而是簡單的假設(shè)棧夠用。
一些輔助庫中的函數(shù)用于檢查 C 函數(shù)的參數(shù)。
因為錯誤信息格式化為指代參數(shù)
(例如,"bad argument #1
"),
你就不要把這些函數(shù)用于參數(shù)之外的值了。
如果檢查無法通過,
luaL_check*
這些函數(shù)一定會拋出錯誤。
這里我們按字母表次序列出了輔助庫中的所有函數(shù)和類型。
luaL_addchar
[-?, +?, e]
void luaL_addchar (luaL_Buffer *B, char c);
向緩存 B
(參見 luaL_Buffer
)
添加一個字節(jié) c
。
luaL_addlstring
[-?, +?, e]
void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l);
向緩存 B
(參見 luaL_Buffer
)
添加一個長度為 l
的字符串 s
。
這個字符串可以包含零。
luaL_addsize
[-?, +?, e]
void luaL_addsize (luaL_Buffer *B, size_t n);
向緩存 B
(參見 luaL_Buffer
)
添加一個已在之前復(fù)制到緩沖區(qū)(參見 luaL_prepbuffer
)
的長度為 n
的字符串。
luaL_addstring
[-?, +?, e]
void luaL_addstring (luaL_Buffer *B, const char *s);
向緩存 B
(參見 luaL_Buffer
)
添加一個零結(jié)尾的字符串 s
。
luaL_addvalue
[-1, +?, e]
void luaL_addvalue (luaL_Buffer *B);
向緩存 B
(參見 luaL_Buffer
)
添加棧頂?shù)囊粋€值,隨后將其彈出。
這個函數(shù)是操作字符串緩存的函數(shù)中,唯一一個會(且必須)在棧上放置額外元素的。 這個元素將被加入緩存。
luaL_argcheck
[-0, +0, v]
void luaL_argcheck (lua_State *L, int cond, int arg, const char *extramsg);
檢查 cond
是否為真。
如果不為真,以標(biāo)準(zhǔn)信息形式拋出一個錯誤
(參見 luaL_argerror
)。
luaL_argerror
[-0, +0, v]
int luaL_argerror (lua_State *L, int arg, const char *extramsg);
拋出一個錯誤報告調(diào)用的 C 函數(shù)的第 arg
個參數(shù)的問題。
它使用下列標(biāo)準(zhǔn)信息并包含了一段 extramsg
作為注解:
bad argument #arg to 'funcname' (extramsg)
這個函數(shù)永遠(yuǎn)不會返回。
luaL_Buffer
typedef struct luaL_Buffer luaL_Buffer;
字符串緩存 的類型。
字符串緩存可以讓 C 代碼分段構(gòu)造一個 Lua 字符串。 使用模式如下:
luaL_Buffer
的變量 b
。luaL_buffinit(L, &b)
初始化它。luaL_add*
這組函數(shù)向其添加字符串片斷。
luaL_pushresult(&b)
。
最后這次調(diào)用會在棧頂留下最終的字符串。
如果你預(yù)先知道結(jié)果串的長度, 你可以這樣使用緩存:
luaL_Buffer
的變量 b
。luaL_buffinitsize(L, &b, sz)
預(yù)分配 sz
大小的空間。luaL_pushresultsize(&b, sz)
,
這里的 sz
指已經(jīng)復(fù)制到緩存內(nèi)的字符串長度。
一般的操作過程中,字符串緩存會使用不定量的棧槽。
因此,在使用緩存中,你不能假定目前棧頂在哪。
在對緩存操作的函數(shù)調(diào)用間,你都可以使用棧,只需要保證棧平衡即可;
即,在你做一次緩存操作調(diào)用時,當(dāng)時的棧位置和上次調(diào)用緩存操作后的位置相同。
(對于 luaL_addvalue
是個唯一的例外。)
在調(diào)用完 luaL_pushresult
后,
棧會恢復(fù)到緩存初始化時的位置上,并在頂部壓入最終的字符串。
luaL_buffinit
[-0, +0, –]
void luaL_buffinit (lua_State *L, luaL_Buffer *B);
初始化緩存 B
。
這個函數(shù)不會分配任何空間;
緩存必須以一個變量的形式聲明
(參見 luaL_Buffer
)。
luaL_buffinitsize
[-?, +?, e]
char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz);
等價于調(diào)用序列
luaL_buffinit
,
luaL_prepbuffsize
。
luaL_callmeta
[-0, +(0|1), e]
int luaL_callmeta (lua_State *L, int obj, const char *e);
調(diào)用一個元方法。
如果在索引 obj
處的對象有元表,
且元表有域 e
。
這個函數(shù)會以該對象為參數(shù)調(diào)用這個域。
這種情況下,函數(shù)返回真并將調(diào)用返回值壓棧。
如果那個位置沒有元表,或沒有對應(yīng)的元方法,
此函數(shù)返回假(并不會將任何東西壓棧)。
luaL_checkany
[-0, +0, v]
void luaL_checkany (lua_State *L, int arg);
檢查函數(shù)在 arg
位置是否有任何類型(包括 nil)的參數(shù)。
luaL_checkinteger
[-0, +0, v]
lua_Integer luaL_checkinteger (lua_State *L, int arg);
檢查函數(shù)的第 arg
個參數(shù)是否是一個
整數(shù)(或是可以被轉(zhuǎn)換為一個整數(shù))
并以 lua_Integer
類型返回這個整數(shù)值。
luaL_checklstring
[-0, +0, v]
const char *luaL_checklstring (lua_State *L, int arg, size_t *l);
檢查函數(shù)的第 arg
個參數(shù)是否是一個
字符串,并返回該字符串;
如果 l
不為 NULL
,
將字符串的長度填入 *l
。
這個函數(shù)使用 lua_tolstring
來獲取結(jié)果。
所以該函數(shù)有可能引發(fā)的轉(zhuǎn)換都同樣有效。
luaL_checknumber
[-0, +0, v]
lua_Number luaL_checknumber (lua_State *L, int arg);
檢查函數(shù)的第 arg
個參數(shù)是否是一個
數(shù)字,并返回這個數(shù)字。
luaL_checkoption
[-0, +0, v]
int luaL_checkoption (lua_State *L, int arg, const char *def, const char *const lst[]);
檢查函數(shù)的第 arg
個參數(shù)是否是一個
字符串,并在數(shù)組 lst
(比如是零結(jié)尾的字符串?dāng)?shù)組)
中查找這個字符串。
返回匹配到的字符串在數(shù)組中的索引號。
如果參數(shù)不是字符串,或是字符串在數(shù)組中匹配不到,都將拋出錯誤。
如果 def
不為 NULL
,
函數(shù)就把 def
當(dāng)作默認(rèn)值。
默認(rèn)值在參數(shù) arg
不存在,或該參數(shù)是 nil 時生效。
這個函數(shù)通常用于將字符串映射為 C 枚舉量。 (在 Lua 庫中做這個轉(zhuǎn)換可以讓其使用字符串,而不是數(shù)字來做一些選項。)
luaL_checkstack
[-0, +0, v]
void luaL_checkstack (lua_State *L, int sz, const char *msg);
將??臻g擴(kuò)展到 top + sz
個元素。
如果擴(kuò)展不了,則拋出一個錯誤。
msg
是用于錯誤消息的額外文本
(NULL
表示不需要額外文本)。
luaL_checkstring
[-0, +0, v]
const char *luaL_checkstring (lua_State *L, int arg);
檢查函數(shù)的第 arg
個參數(shù)是否是一個
字符串并返回這個字符串。
這個函數(shù)使用 lua_tolstring
來獲取結(jié)果。
所以該函數(shù)有可能引發(fā)的轉(zhuǎn)換都同樣有效。
luaL_checktype
[-0, +0, v]
void luaL_checktype (lua_State *L, int arg, int t);
檢查函數(shù)的第 arg
個參數(shù)的類型是否是 t
。
參見 lua_type
查閱類型 t
的編碼。
luaL_checkudata
[-0, +0, v]
void *luaL_checkudata (lua_State *L, int arg, const char *tname);
檢查函數(shù)的第 arg
個參數(shù)是否是一個類型為
tname
的用戶數(shù)據(jù)
(參見 luaL_newmetatable
)。
它會返回該用戶數(shù)據(jù)的地址
(參見 lua_touserdata
)。
luaL_checkversion
[-0, +0, –]
void luaL_checkversion (lua_State *L);
檢查調(diào)用它的內(nèi)核是否是創(chuàng)建這個 Lua 狀態(tài)機的內(nèi)核。 以及調(diào)用它的代碼是否使用了相同的 Lua 版本。 同時也檢查調(diào)用它的內(nèi)核與創(chuàng)建該 Lua 狀態(tài)機的內(nèi)核 是否使用了同一片地址空間。
luaL_dofile
[-0, +?, e]
int luaL_dofile (lua_State *L, const char *filename);
加載并運行指定的文件。 它是用下列宏定義出來:
(luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
如果沒有錯誤,函數(shù)返回假; 有錯則返回真。
luaL_dostring
[-0, +?, –]
int luaL_dostring (lua_State *L, const char *str);
加載并運行指定的字符串。 它是用下列宏定義出來:
(luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))
如果沒有錯誤,函數(shù)返回假; 有錯則返回真。
luaL_error
[-0, +0, v]
int luaL_error (lua_State *L, const char *fmt, ...);
拋出一個錯誤。
錯誤消息的格式由 fmt
給出。
后面需提供若干參數(shù),
這些參數(shù)遵循 lua_pushfstring
中的規(guī)則。
如果能獲得相關(guān)信息,它還會在消息前面加上錯誤發(fā)生時的文件名及行號。
這個函數(shù)永遠(yuǎn)不會返回。
但是在 C 函數(shù)中通常遵循慣用法:
return luaL_error(args)
。
luaL_execresult
[-0, +3, e]
int luaL_execresult (lua_State *L, int stat);
這個函數(shù)用于生成標(biāo)準(zhǔn)庫中和進(jìn)程相關(guān)函數(shù)的返回值。
(指 os.execute
和 io.close
)。
luaL_fileresult
[-0, +(1|3), e]
int luaL_fileresult (lua_State *L, int stat, const char *fname);
這個函數(shù)用于生成標(biāo)準(zhǔn)庫中和文件相關(guān)的函數(shù)的返回值。
(指 (io.open
,
os.rename
,
file:seek
,等。)。
luaL_getmetafield
[-0, +(0|1), e]
int luaL_getmetafield (lua_State *L, int obj, const char *e);
將索引 obj
處對象的元表中 e
域的值壓棧。
如果該對象沒有元表,或是該元表沒有相關(guān)域,
此函數(shù)什么也不會壓棧并返回 LUA_TNIL
。
luaL_getmetatable
[-0, +1, –]
int luaL_getmetatable (lua_State *L, const char *tname);
將注冊表中 tname
對應(yīng)的元表
(參見 luaL_newmetatable
)壓棧。
如果沒有 tname
對應(yīng)的元表,則將 nil 壓棧并返回假。
luaL_getsubtable
[-0, +1, e]
int luaL_getsubtable (lua_State *L, int idx, const char *fname);
確保 t[fname]
是一張表,并將這張表壓棧。
這里的 t
指索引 idx
處的值。
如果它原來就是一張表,返回真;
否則為它創(chuàng)建一張新表,返回假。
luaL_gsub
[-0, +1, e]
const char *luaL_gsub (lua_State *L, const char *s, const char *p, const char *r);
將字符串 s
生成一個副本,
并將其中的所有字符串 p
都替換為字符串 r
。
將結(jié)果串壓棧并返回它。
luaL_len
[-0, +0, e]
lua_Integer luaL_len (lua_State *L, int index);
以數(shù)字形式返回給定索引處值的“長度”;
它等價于在 Lua 中調(diào)用 '#
' 的操作
(參見 §3.4.7)。
如果操作結(jié)果不是一個整數(shù),則拋出一個錯誤。
(這種情況只發(fā)生在觸發(fā)元方法時。)
luaL_loadbuffer
[-0, +1, –]
int luaL_loadbuffer (lua_State *L, const char *buff, size_t sz, const char *name);
等價于 luaL_loadbufferx
,
其 mode
參數(shù)等于 NULL
。
luaL_loadbufferx
[-0, +1, –]
int luaL_loadbufferx (lua_State *L, const char *buff, size_t sz, const char *name, const char *mode);
把一段緩存加載為一個 Lua 代碼塊。
這個函數(shù)使用 lua_load
來加載 buff
指向的長度為 sz
的內(nèi)存區(qū)。
這個函數(shù)和 lua_load
返回值相同。
name
作為代碼塊的名字,用于調(diào)試信息和錯誤消息。
mode
字符串的作用同函數(shù) lua_load
。
luaL_loadfile
[-0, +1, e]
int luaL_loadfile (lua_State *L, const char *filename);
等價于 luaL_loadfilex
,
其 mode
參數(shù)等于 NULL
。
luaL_loadfilex
[-0, +1, e]
int luaL_loadfilex (lua_State *L, const char *filename, const char *mode);
把一個文件加載為 Lua 代碼塊。
這個函數(shù)使用 lua_load
加載文件中的數(shù)據(jù)。
代碼塊的名字被命名為 filename
。
如果 filename
為 NULL
,
它從標(biāo)準(zhǔn)輸入加載。
如果文件的第一行以 #
打頭,則忽略這一行。
mode
字符串的作用同函數(shù) lua_load
。
此函數(shù)的返回值和 lua_load
相同,
不過它還可能產(chǎn)生一個叫做 LUA_ERRFILE
的出錯碼。這種錯誤發(fā)生于無法打開或讀入文件時,或是文件的模式錯誤。
和 lua_load
一樣,這個函數(shù)僅加載代碼塊不運行。
luaL_loadstring
[-0, +1, –]
int luaL_loadstring (lua_State *L, const char *s);
將一個字符串加載為 Lua 代碼塊。
這個函數(shù)使用 lua_load
加載一個零結(jié)尾的字符串
s
。
此函數(shù)的返回值和 lua_load
相同。
也和 lua_load
一樣,這個函數(shù)僅加載代碼塊不運行。
luaL_newlib
[-0, +1, e]
void luaL_newlib (lua_State *L, const luaL_Reg l[]);
創(chuàng)建一張新的表,并把列表 l
中的函數(shù)注冊進(jìn)去。
它是用下列宏實現(xiàn)的:
(luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
數(shù)組 l
必須是一個數(shù)組,而不能是一個指針。
luaL_newlibtable
[-0, +1, e]
void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);
創(chuàng)建一張新的表,并預(yù)分配足夠保存下數(shù)組 l
內(nèi)容的空間(但不填充)。
這是給 luaL_setfuncs
一起用的
(參見 luaL_newlib
)。
它以宏形式實現(xiàn),
數(shù)組 l
必須是一個數(shù)組,而不能是一個指針。
luaL_newmetatable
[-0, +1, e]
int luaL_newmetatable (lua_State *L, const char *tname);
如果注冊表中已存在鍵 tname
,返回 0 。
否則,
為用戶數(shù)據(jù)的元表創(chuàng)建一張新表。
向這張表加入 __name = tname
鍵值對,
并將 [tname] = new table
添加到注冊表中,
返回 1 。
(__name
項可用于一些錯誤輸出函數(shù)。)
這兩種情況都會把最終的注冊表中關(guān)聯(lián) tname
的值壓棧。
luaL_newstate
[-0, +0, –]
lua_State *luaL_newstate (void);
創(chuàng)建一個新的 Lua 狀態(tài)機。
它以一個基于標(biāo)準(zhǔn) C 的 realloc
函數(shù)實現(xiàn)的內(nèi)存分配器
調(diào)用 lua_newstate
。
并把可打印一些出錯信息到標(biāo)準(zhǔn)錯誤輸出的 panic 函數(shù)(參見 §4.6)
設(shè)置好,用于處理致命錯誤。
返回新的狀態(tài)機。
如果內(nèi)存分配失敗,則返回 NULL
。
luaL_openlibs
[-0, +0, e]
void luaL_openlibs (lua_State *L);
打開指定狀態(tài)機中的所有 Lua 標(biāo)準(zhǔn)庫。
luaL_optinteger
[-0, +0, v]
lua_Integer luaL_optinteger (lua_State *L, int arg, lua_Integer d);
如果函數(shù)的第 arg
個參數(shù)是一個
整數(shù)(或可以轉(zhuǎn)換為一個整數(shù)),
返回該整數(shù)。
若該參數(shù)不存在或是 nil,
返回 d
。
除此之外的情況,拋出錯誤。
luaL_optlstring
[-0, +0, v]
const char *luaL_optlstring (lua_State *L, int arg, const char *d, size_t *l);
如果函數(shù)的第 arg
個參數(shù)是一個
字符串,返回該字符串。
若該參數(shù)不存在或是 nil,
返回 d
。
除此之外的情況,拋出錯誤。
若 l
不為 NULL
,
將結(jié)果的長度填入 *l
。
luaL_optnumber
[-0, +0, v]
lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number d);
如果函數(shù)的第 arg
個參數(shù)是一個
數(shù)字,返回該數(shù)字。
若該參數(shù)不存在或是 nil,
返回 d
。
除此之外的情況,拋出錯誤。
luaL_optstring
[-0, +0, v]
const char *luaL_optstring (lua_State *L, int arg, const char *d);
如果函數(shù)的第 arg
個參數(shù)是一個
字符串,返回該字符串。
若該參數(shù)不存在或是 nil,
返回 d
。
除此之外的情況,拋出錯誤。
luaL_prepbuffer
[-?, +?, e]
char *luaL_prepbuffer (luaL_Buffer *B);
等價于 luaL_prepbuffsize
,
其預(yù)定義大小為 LUAL_BUFFERSIZE
。
luaL_prepbuffsize
[-?, +?, e]
char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz);
返回一段大小為 sz
的空間地址。
你可以將字符串復(fù)制其中以加到緩存 B
內(nèi)
(參見 luaL_Buffer
)。
將字符串復(fù)制其中后,你必須調(diào)用 luaL_addsize
傳入字符串的大小,才會真正把它加入緩存。
luaL_pushresult
[-?, +1, e]
void luaL_pushresult (luaL_Buffer *B);
結(jié)束對緩存 B
的使用,將最終的字符串留在棧頂。
luaL_pushresultsize
[-?, +1, e]
void luaL_pushresultsize (luaL_Buffer *B, size_t sz);
等價于 luaL_addsize
,luaL_pushresult
。
luaL_ref
[-1, +0, e]
int luaL_ref (lua_State *L, int t);
針對棧頂?shù)膶ο?,?chuàng)建并返回一個在索引 t
指向的表中的 引用
(最后會彈出棧頂對象)。
此引用是一個唯一的整數(shù)鍵。
只要你不向表 t
手工添加整數(shù)鍵,
luaL_ref
可以保證它返回的鍵的唯一性。
你可以通過調(diào)用 lua_rawgeti(L, t, r)
來找回由
r
引用的對象。
函數(shù) luaL_unref
用來釋放一個引用關(guān)聯(lián)的對象
如果棧頂?shù)膶ο笫?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
注冊函數(shù)的數(shù)組類型。
name
指函數(shù)名,func
是函數(shù)指針。
任何 luaL_Reg
數(shù)組必須以一對
name
與 func
皆為 NULL
結(jié)束。
luaL_requiref
[-0, +1, e]
void luaL_requiref (lua_State *L, const char *modname, lua_CFunction openf, int glb);
如果 modname
不在 package.loaded
中,
則調(diào)用函數(shù) openf
,并傳入字符串 modname
。
將其返回值置入 package.loaded[modname]
。
這個行為好似該函數(shù)通過 require
調(diào)用過一樣。
如果 glb
為真,
同時也將模塊設(shè)到全局變量 modname
里。
在棧上留下該模塊的副本。
luaL_setfuncs
[-nup, +0, e]
void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
把數(shù)組 l
中的所有函數(shù)
(參見 luaL_Reg
)
注冊到棧頂?shù)谋碇校ㄔ摫碓诳蛇x的上值之下,見下面的解說)。
若 nup
不為零,
所有的函數(shù)都共享 nup
個上值。
這些值必須在調(diào)用之前,壓在表之上。
這些值在注冊完畢后都會從棧彈出。
luaL_setmetatable
[-0, +0, –]
void luaL_setmetatable (lua_State *L, const char *tname);
將注冊表中 tname
關(guān)聯(lián)元表
(參見 luaL_newmetatable
)
設(shè)為棧頂對象的元表。
luaL_Stream
typedef struct luaL_Stream { FILE *f; lua_CFunction closef; } luaL_Stream;
標(biāo)準(zhǔn)輸入輸出庫中用到的標(biāo)準(zhǔn)文件句柄結(jié)構(gòu)。
文件句柄實現(xiàn)為一個完全用戶數(shù)據(jù),
其元表被稱為 LUA_FILEHANDLE
(LUA_FILEHANDLE
是一個代表真正元表的名字的宏)。
這張元表由標(biāo)準(zhǔn)輸入輸出庫(參見 luaL_newmetatable
)創(chuàng)建。
用戶數(shù)據(jù)必須以結(jié)構(gòu) luaL_Stream
開頭;
此結(jié)構(gòu)其后可以包含任何其它數(shù)據(jù)。
f
域指向一個 C 數(shù)據(jù)流
(如果它為 NULL
表示一個沒有創(chuàng)建好的句柄)。
closef
域指向一個在關(guān)閉或回收該流時需要調(diào)用的 Lua 函數(shù)。
該函數(shù)將收到一個參數(shù),即文件句柄。
它需要返回 true(操作成功)或
nil 加錯誤消息(出錯的時候)。
一旦 Lua 調(diào)用過這個域,該域的值就會修改為 NULL
以提示這個句柄已經(jīng)被關(guān)閉了。
luaL_testudata
[-0, +0, e]
void *luaL_testudata (lua_State *L, int arg, const char *tname);
此函數(shù)和 luaL_checkudata
類似。
但它在測試失敗時會返回 NULL
而不是拋出錯誤。
luaL_tolstring
[-0, +1, e]
const char *luaL_tolstring (lua_State *L, int idx, size_t *len);
將給定索引處的 Lua 值轉(zhuǎn)換為一個相應(yīng)格式的 C 字符串。
結(jié)果串不僅會壓棧,還會由函數(shù)返回。
如果 len
不為 NULL
,
它還把字符串長度設(shè)到 *len
中。
如果該值有一個帶 "__tostring"
域的元表,
luaL_tolstring
會以該值為參數(shù)去調(diào)用對應(yīng)的元方法,
并將其返回值作為結(jié)果。
luaL_traceback
[-0, +1, e]
void luaL_traceback (lua_State *L, lua_State *L1, const char *msg, int level);
將棧 L1
的?;厮菪畔簵?。
如果 msg
不為 NULL
,它會附加到?;厮菪畔⒅?。
level
參數(shù)指明從第幾層開始做?;厮?。
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, e]
void luaL_where (lua_State *L, int lvl);
將一個用于表示 lvl
層棧的控制點位置的字符串壓棧。
這個字符串遵循下面的格式:
chunkname:currentline:
0 層指當(dāng)前正在運行的函數(shù), 1 層指調(diào)用正在運行函數(shù)的函數(shù), 依次類推。
這個函數(shù)用于構(gòu)建錯誤消息的前綴。
標(biāo)準(zhǔn)庫提供了一些有用的函數(shù),
它們都是直接用 C API 實現(xiàn)的。
其中一些函數(shù)提供了原本語言就有的服務(wù)
(例如,type
與 getmetatable
);
另一些提供和“外部”打交道的服務(wù)(例如 I/O );
還有些本可以用 Lua 本身來實現(xiàn),但在 C 中實現(xiàn)可以滿足關(guān)鍵點上的性能需求
(例如 table.sort
)。
所有的庫都是直接用 C API 實現(xiàn)的,并以分離的 C 模塊形式提供。 目前,Lua 有下列標(biāo)準(zhǔn)庫:
除了基礎(chǔ)庫和包管理庫, 其它庫都把自己的函數(shù)放在一張全局表的域中, 或是以對象方法的形式提供。
要使用這些庫,
C 的宿主程序需要先調(diào)用一下
luaL_openlibs
這個函數(shù),
這樣就能打開所有的標(biāo)準(zhǔn)庫。
或者宿主程序也可以用
luaL_requiref
分別打開這些庫:
luaopen_base
(基礎(chǔ)庫),
luaopen_package
(包管理庫),
luaopen_coroutine
(協(xié)程庫),
luaopen_string
(字符串庫),
luaopen_utf8
(UTF8 庫),
luaopen_table
(表處理庫),
luaopen_math
(數(shù)學(xué)庫),
luaopen_io
(I/O 庫),
luaopen_os
(操作系統(tǒng)庫),
luaopen_debug
(調(diào)試庫)。
這些函數(shù)都定義在 lualib.h
中。
基礎(chǔ)庫提供了 Lua 核心函數(shù)。 如果你不將這個庫包含在你的程序中, 你就需要小心檢查程序是否需要自己提供其中一些特性的實現(xiàn)。
assert (v [, message])
如果其參數(shù) v
的值為假(nil 或 false),
它就調(diào)用 error
;
否則,返回所有的參數(shù)。
在錯誤情況時,
message
指那個錯誤對象;
如果不提供這個參數(shù),參數(shù)默認(rèn)為 "assertion failed!
" 。
collectgarbage ([opt [, arg]])
這個函數(shù)是垃圾收集器的通用接口。
通過參數(shù) opt
它提供了一組不同的功能:
collect
":
做一次完整的垃圾收集循環(huán)。
這是默認(rèn)選項。
stop
":
停止垃圾收集器的運行。
在調(diào)用重啟前,收集器只會因顯式的調(diào)用運行。
restart
":
重啟垃圾收集器的自動運行。
count
":
以 K 字節(jié)數(shù)為單位返回 Lua 使用的總內(nèi)存數(shù)。
這個值有小數(shù)部分,所以只需要乘上 1024 就能得到
Lua 使用的準(zhǔn)確字節(jié)數(shù)(除非溢出)。
step
":
單步運行垃圾收集器。
步長“大小”由 arg
控制。
傳入 0 時,收集器步進(jìn)(不可分割的)一步。
傳入非 0 值,
收集器收集相當(dāng)于 Lua 分配這些多(K 字節(jié))內(nèi)存的工作。
如果收集器結(jié)束一個循環(huán)將返回 true 。
setpause
":
將 arg
設(shè)為收集器的 間歇率
(參見 §2.5)。
返回 間歇率 的前一個值。
setstepmul
":
將 arg
設(shè)為收集器的 步進(jìn)倍率
(參見 §2.5)。
返回 步進(jìn)倍率 的前一個值。
isrunning
":
返回表示收集器是否在工作的布爾值
(即未被停止)。
dofile ([filename])
dofile
執(zhí)行標(biāo)準(zhǔn)輸入的內(nèi)容(stdin
)。
返回該代碼塊的所有返回值。
對于有錯誤的情況,dofile
將錯誤反饋給調(diào)用者
(即,dofile
沒有運行在保護(hù)模式下)。
error (message [, level])
message
返回。
函數(shù) error
永遠(yuǎn)不會返回。
當(dāng) message 是一個字符串時,通常 error
會把一些有關(guān)出錯位置的信息附加在消息的前頭。
level
參數(shù)指明了怎樣獲得出錯位置。
對于 level 1 (默認(rèn)值),出錯位置指 error
函數(shù)調(diào)用的位置。
Level 2 將出錯位置指向調(diào)用 error
的函數(shù)的函數(shù);以此類推。
傳入 level 0 可以避免在消息前添加出錯位置信息。
_G
getmetatable (object)
如果 object
不包含元表,返回 nil 。
否則,如果在該對象的元表中有 "__metatable"
域時返回其關(guān)聯(lián)值,
沒有時返回該對象的元表。
ipairs (t)
返回三個值(迭代函數(shù)、表 t
以及 0 ),
如此,以下代碼
for i,v in ipairs(t) do body end
將迭代鍵值對(1,t[1]
) ,(2,t[2]
), ... ,直到第一個空值。
load (chunk [, chunkname [, mode [, env]]])
加載一個代碼塊。
如果 chunk
是一個字符串,代碼塊指這個字符串。
如果 chunk
是一個函數(shù),
load
不斷地調(diào)用它獲取代碼塊的片斷。
每次對 chunk
的調(diào)用都必須返回一個字符串緊緊連接在上次調(diào)用的返回串之后。
當(dāng)返回空串、nil、或是不返回值時,都表示代碼塊結(jié)束。
如果沒有語法錯誤, 則以函數(shù)形式返回編譯好的代碼塊; 否則,返回 nil 加上錯誤消息。
如果結(jié)果函數(shù)有上值,
env
被設(shè)為第一個上值。
若不提供此參數(shù),將全局環(huán)境替代它。
所有其它上值初始化為 nil。
(當(dāng)你加載主代碼塊時候,結(jié)果函數(shù)一定有且僅有一個上值 _ENV
(參見 §2.2))。
然而,如果你加載一個用函數(shù)(參見 string.dump
,
結(jié)果函數(shù)可以有任意數(shù)量的上值)
創(chuàng)建出來的二進(jìn)制代碼塊時,所有的上值都是新創(chuàng)建出來的。
也就是說它們不會和別的任何函數(shù)共享。
chunkname
在錯誤消息和調(diào)試消息中(參見 §4.9),用于代碼塊的名字。
如果不提供此參數(shù),它默認(rèn)為字符串chunk
。
chunk
不是字符串時,則為 "=(load)
" 。
字符串 mode
用于控制代碼塊是文本還是二進(jìn)制(即預(yù)編譯代碼塊)。
它可以是字符串 "b
" (只能是二進(jìn)制代碼塊),
"t
" (只能是文本代碼塊),
或 "bt
" (可以是二進(jìn)制也可以是文本)。
默認(rèn)值為 "bt
"。
Lua 不會對二進(jìn)制代碼塊做健壯性檢查。 惡意構(gòu)造一個二進(jìn)制塊有可能把解釋器弄崩潰。
loadfile ([filename [, mode [, env]]])
和 load
類似,
不過是從文件 filename
或標(biāo)準(zhǔn)輸入(如果文件名未提供)中獲取代碼塊。
next (table [, index])
運行程序來遍歷表中的所有域。
第一個參數(shù)是要遍歷的表,第二個參數(shù)是表中的某個鍵。
next
返回該鍵的下一個鍵及其關(guān)聯(lián)的值。
如果用 nil 作為第二個參數(shù)調(diào)用 next
將返回初始鍵及其關(guān)聯(lián)值。
當(dāng)以最后一個鍵去調(diào)用,或是以 nil 調(diào)用一張空表時,
next
返回 nil。
如果不提供第二個參數(shù),將認(rèn)為它就是 nil。
特別指出,你可以用 next(t)
來判斷一張表是否是空的。
索引在遍歷過程中的次序無定義, 即使是數(shù)字索引也是這樣。 (如果想按數(shù)字次序遍歷表,可以使用數(shù)字形式的 for 。)
當(dāng)在遍歷過程中你給表中并不存在的域賦值,
next
的行為是未定義的。
然而你可以去修改那些已存在的域。
特別指出,你可以清除一些已存在的域。
pairs (t)
如果 t
有元方法 __pairs
,
以 t
為參數(shù)調(diào)用它,并返回其返回的前三個值。
否則,返回三個值:next
函數(shù),
表 t
,以及 nil。
因此以下代碼
for k,v in pairs(t) do body end
能迭代表 t
中的所有鍵值對。
參見函數(shù) next
中關(guān)于迭代過程中修改表的風(fēng)險。
pcall (f [, arg1, ···])
傳入?yún)?shù),以 保護(hù)模式 調(diào)用函數(shù) f
。
這意味著 f
中的任何錯誤不會拋出;
取而代之的是,pcall
會將錯誤捕獲到,并返回一個狀態(tài)碼。
第一個返回值是狀態(tài)碼(一個布爾量),
當(dāng)沒有錯誤時,其為真。
此時,pcall
同樣會在狀態(tài)碼后返回所有調(diào)用的結(jié)果。
在有錯誤時,pcall
返回 false 加錯誤消息。
print (···)
stdout
。
它用 tostring
函數(shù)將每個參數(shù)都轉(zhuǎn)換為字符串。
print
不用于做格式化輸出。僅作為看一下某個值的快捷方式。
多用于調(diào)試。
完整的對輸出的控制,請使用 string.format
以及 io.write
。
rawequal (v1, v2)
v1
是否和 v2
相等。
返回一個布爾量。
rawget (table, index)
table[index]
的值。
table
必須是一張表;
index
可以是任何值。
rawlen (v)
v
的長度。
v
可以是表或字符串。
它返回一個整數(shù)。
rawset (table, index, value)
table[index]
設(shè)為 value
。
table
必須是一張表,
index
可以是 nil 與 NaN 之外的任何值。
value
可以是任何 Lua 值。
這個函數(shù)返回 table
。
select (index, ···)
如果 index
是個數(shù)字,
那么返回參數(shù)中第 index
個之后的部分;
負(fù)的數(shù)字會從后向前索引(-1 指最后一個參數(shù))。
否則,index
必須是字符串 "#"
,
此時 select
返回參數(shù)的個數(shù)。
setmetatable (table, metatable)
給指定表設(shè)置元表。
(你不能在 Lua 中改變其它類型值的元表,那些只能在 C 里做。)
如果 metatable
是 nil,
將指定表的元表移除。
如果原來那張元表有 "__metatable"
域,拋出一個錯誤。
這個函數(shù)返回 table
。
tonumber (e [, base])
如果調(diào)用的時候沒有 base
,
tonumber
嘗試把參數(shù)轉(zhuǎn)換為一個數(shù)字。
如果參數(shù)已經(jīng)是一個數(shù)字,或是一個可以轉(zhuǎn)換為數(shù)字的字符串,
tonumber
就返回這個數(shù)字;
否則返回 nil。
字符串的轉(zhuǎn)換結(jié)果可能是整數(shù)也可能是浮點數(shù), 這取決于 Lua 的轉(zhuǎn)換文法(參見 §3.1)。 (字符串可以有前置和后置的空格,可以帶符號。)
當(dāng)傳入 base
調(diào)用它時,
e
必須是一個以該進(jìn)制表示的整數(shù)字符串。
進(jìn)制可以是 2 到 36 (包含 2 和 36)之間的任何整數(shù)。
大于 10 進(jìn)制時,字母 'A
' (大小寫均可)表示 10 ,
'B
' 表示 11,依次到 'Z
' 表示 35 。
如果字符串 e
不是該進(jìn)制下的合法數(shù)字,
函數(shù)返回 nil。
tostring (v)
string.format
。)
如果 v
有 "__tostring"
域的元表,
tostring
會以 v
為參數(shù)調(diào)用它。
并用它的結(jié)果作為返回值。
type (v)
nil
" (一個字符串,而不是 nil 值),
"number
",
"string
",
"boolean
",
"table
",
"function
",
"thread
",
"userdata
"。
_VERSION
Lua 5.3
"。
xpcall (f, msgh [, arg1, ···])
這個函數(shù)和 pcall
類似。
不過它可以額外設(shè)置一個消息處理器 msgh
。
關(guān)于協(xié)程的操作作為基礎(chǔ)庫的一個子庫,
被放在一個獨立表 coroutine
中。
協(xié)程的介紹參見 §2.6 。
coroutine.create (f)
創(chuàng)建一個主體函數(shù)為 f
的新協(xié)程。
f
必須是一個 Lua 的函數(shù)。
返回這個新協(xié)程,它是一個類型為 "thread"
的對象。
coroutine.isyieldable ()
如果正在運行的協(xié)程可以讓出,則返回真。
不在主線程中或不在一個無法讓出的 C 函數(shù)中時,當(dāng)前協(xié)程是可讓出的。
coroutine.resume (co [, val1, ···])
開始或繼續(xù)協(xié)程 co
的運行。
當(dāng)你第一次延續(xù)一個協(xié)程,它會從主體函數(shù)處開始運行。
val1
, ... 這些值會以參數(shù)形式傳入主體函數(shù)。
如果該協(xié)程被讓出,resume
會重新啟動它;
val1
, ... 這些參數(shù)會作為讓出點的返回值。
如果協(xié)程運行起來沒有錯誤,
resume
返回 true 加上傳給 yield
的所有值
(當(dāng)協(xié)程讓出),
或是主體函數(shù)的所有返回值(當(dāng)協(xié)程中止)。
如果有任何錯誤發(fā)生,
resume
返回 false 加錯誤消息。
coroutine.running ()
返回當(dāng)前正在運行的協(xié)程加一個布爾量。 如果當(dāng)前運行的協(xié)程是主線程,其為真。
coroutine.status (co)
以字符串形式返回協(xié)程 co
的狀態(tài):
當(dāng)協(xié)程正在運行(它就是調(diào)用 status
的那個) ,返回 "running"
;
如果協(xié)程調(diào)用 yield
掛起或是還沒有開始運行,返回 "suspended"
;
如果協(xié)程是活動的,但并不在運行(即它正在延續(xù)其它協(xié)程),返回 "normal"
;
如果協(xié)程運行完主體函數(shù)或因錯誤停止,返回 "dead"
。
coroutine.wrap (f)
創(chuàng)建一個主體函數(shù)為 f
的新協(xié)程。
f
必須是一個 Lua 的函數(shù)。
返回一個函數(shù),
每次調(diào)用該函數(shù)都會延續(xù)該協(xié)程。
傳給這個函數(shù)的參數(shù)都會作為 resume
的額外參數(shù)。
和 resume
返回相同的值,
只是沒有第一個布爾量。
如果發(fā)生任何錯誤,拋出這個錯誤。
coroutine.yield (···)
掛起正在調(diào)用的協(xié)程的執(zhí)行。
傳遞給 yield
的參數(shù)都會轉(zhuǎn)為 resume
的額外返回值。
包管理庫提供了從 Lua 中加載模塊的基礎(chǔ)庫。
只有一個導(dǎo)出函數(shù)直接放在全局環(huán)境中:
require
。
所有其它的部分都導(dǎo)出在表 package
中。
require (modname)
加載一個模塊。
這個函數(shù)首先查找 package.loaded
表,
檢測 modname
是否被加載過。
如果被加載過,require
返回 package.loaded[modname]
中保存的值。
否則,它試著為模塊尋找 加載器 。
require
遵循 package.searchers
序列的指引來查找加載器。
如果改變這個序列,我們可以改變 require
如何查找一個模塊。
下列說明基于 package.searchers
的默認(rèn)配置。
首先 require
查找 package.preload[modname]
。
如果這里有一個值,這個值(必須是一個函數(shù))就是那個加載器。
否則 require
使用 Lua 加載器去查找
package.path
的路徑。
如果查找失敗,接著使用 C 加載器去查找
package.cpath
的路徑。
如果都失敗了,再嘗試 一體化 加載器 (參見 package.searchers
)。
每次找到一個加載器,require
都用兩個參數(shù)調(diào)用加載器:
modname
和一個在獲取加載器過程中得到的參數(shù)。
(如果通過查找文件得到的加載器,這個額外參數(shù)是文件名。)
如果加載器返回非空值,
require
將這個值賦給 package.loaded[modname]
。
如果加載器沒能返回一個非空值用于賦給 package.loaded[modname]
,
require
會在那里設(shè)入 true 。
無論是什么情況,require
都會返回
package.loaded[modname]
的最終值。
如果在加載或運行模塊時有錯誤,
或是無法為模塊找到加載器,
require
都會拋出錯誤。
package.config
一個描述有一些為包管理準(zhǔn)備的編譯期配置信息的串。 這個字符串由一系列行構(gòu)成:
\
' ,對于其它系統(tǒng)是 '/
' 。;
' 。?
' 。!
' 。luaopen_
函數(shù)名時被忽略掉。
默認(rèn)是 '-
'。
package.cpath
這個路徑被 require
在 C 加載器中做搜索時用到。
Lua 用和初始化 Lua 路徑 package.path
相同的方式初始化 C 路徑 package.cpath
。
它會使用環(huán)境變量 LUA_CPATH_5_3
或
環(huán)境變量 LUA_CPATH
初始化。
要么就采用 luaconf.h
中定義的默認(rèn)路徑。
package.loaded
用于 require
控制哪些模塊已經(jīng)被加載的表。
當(dāng)你請求一個 modname
模塊,且
package.loaded[modname]
不為假時,
require
簡單返回儲存在內(nèi)的值。
這個變量僅僅是對真正那張表的引用;
改變這個值并不會改變 require
使用的表。
package.loadlib (libname, funcname)
讓宿主程序動態(tài)鏈接 C 庫 libname
。
當(dāng) funcname
為 "*
",
它僅僅連接該庫,讓庫中的符號都導(dǎo)出給其它動態(tài)鏈接庫使用。
否則,它查找?guī)熘械暮瘮?shù) funcname
,以 C 函數(shù)的形式返回這個函數(shù)。
因此,funcname
必須遵循原型 lua_CFunction
(參見 lua_CFunction
)。
這是一個低階函數(shù)。
它完全繞過了包模塊系統(tǒng)。
和 require
不同,
它不會做任何路徑查詢,也不會自動加擴(kuò)展名。
libname
必須是一個 C 庫需要的完整的文件名,如果有必要,需要提供路徑和擴(kuò)展名。
funcname
必須是 C 庫需要的準(zhǔn)確名字
(這取決于使用的 C 編譯器和鏈接器)。
這個函數(shù)在標(biāo)準(zhǔn) C 中不支持。
因此,它只在部分平臺有效
( Windows ,Linux ,Mac OS X, Solaris, BSD, 加上支持
dlfcn
標(biāo)準(zhǔn)的 Unix 系統(tǒng))。
package.path
這個路徑被 require
在 Lua 加載器中做搜索時用到。
在啟動時,Lua 用環(huán)境變量 LUA_PATH_5_3
或環(huán)境變量 LUA_PATH
來初始化這個變量。
或采用 luaconf.h
中的默認(rèn)路徑。
環(huán)境變量中出現(xiàn)的所有 ";;
" 都會被替換成默認(rèn)路徑。
package.preload
保存有一些特殊模塊的加載器
(參見 require
)。
這個變量僅僅是對真正那張表的引用;
改變這個值并不會改變 require
使用的表。
package.searchers
用于 require
控制如何加載模塊的表。
這張表內(nèi)的每一項都是一個 查找器函數(shù)。
當(dāng)查找一個模塊時,
require
按次序調(diào)用這些查找器,
并傳入模塊名(require
的參數(shù))作為唯一的一個參數(shù)。
此函數(shù)可以返回另一個函數(shù)(模塊的 加載器)加上另一個將傳遞給這個加載器的參數(shù)。
或是返回一個描述為何沒有找到這個模塊的字符串
(或是返回 nil 什么也不想說)。
Lua 用四個查找器函數(shù)初始化這張表。
第一個查找器就是簡單的在 package.preload
表中查找加載器。
第二個查找器用于查找 Lua 庫的加載庫。
它使用儲存在 package.path
中的路徑來做查找工作。
查找過程和函數(shù) package.searchpath
描述的一致。
第三個查找器用于查找 C 庫的加載庫。
它使用儲存在 package.cpath
中的路徑來做查找工作。
同樣,
查找過程和函數(shù) package.searchpath
描述的一致。
例如,如果 C 路徑是這樣一個字符串
"./?.so;./?.dll;/usr/local/?/init.so"
查找器查找模塊 foo
會依次嘗試打開文件 ./foo.so
,./foo.dll
,
以及 /usr/local/foo/init.so
。
一旦它找到一個 C 庫,
查找器首先使用動態(tài)鏈接機制連接該庫。
然后嘗試在該庫中找到可以用作加載器的 C 函數(shù)。
這個 C 函數(shù)的名字是 "luaopen_
" 緊接模塊名的字符串,
其中字符串中所有的下劃線都會被替換成點。
此外,如果模塊名中有橫線,
橫線后面的部分(包括橫線)都被去掉。
例如,如果模塊名為 a.b.c-v2.1
,
函數(shù)名就是 luaopen_a_b_c
。
第四個搜索器是 一體化加載器。
它從 C 路徑中查找指定模塊的根名字。
例如,當(dāng)請求 a.b.c
時,
它將查找 a
這個 C 庫。
如果找得到,它會在里面找子模塊的加載函數(shù)。
在我們的例子中,就是找 luaopen_a_b_c
。
利用這個機制,可以把若干 C 子模塊打包進(jìn)單個庫。
每個子模塊都可以有原本的加載函數(shù)名。
除了第一個(預(yù)加載)搜索器外,每個搜索器都會返回
它找到的模塊的文件名。
這和 package.searchpath
的返回值一樣。
第一個搜索器沒有返回值。
package.searchpath (name, path [, sep [, rep]])
在指定 path
中搜索指定的 name
。
路徑是一個包含有一系列以分號分割的 模板 構(gòu)成的字符串。
對于每個模板,都會用 name
替換其中的每個問號(如果有的話)。
且將其中的 sep
(默認(rèn)是點)替換為 rep
(默認(rèn)是系統(tǒng)的目錄分割符)。
然后嘗試打開這個文件名。
例如,如果路徑是字符串
"./?.lua;./?.lc;/usr/local/?/init.lua"
搜索 foo.a
這個名字將
依次嘗試打開文件
./foo/a.lua
, ./foo/a.lc
,以及
/usr/local/foo/a/init.lua
。
返回第一個可以用讀模式打開(并馬上關(guān)閉該文件)的文件的名字。 如果不存在這樣的文件,返回 nil 加上錯誤消息。 (這條錯誤消息列出了所有嘗試打開的文件名。)
這個庫提供了字符串處理的通用函數(shù)。 例如字符串查找、子串、模式匹配等。 當(dāng)在 Lua 中對字符串做索引時,第一個字符從 1 開始計算(而不是 C 里的 0 )。 索引可以是負(fù)數(shù),它指從字符串末尾反向解析。 即,最后一個字符在 -1 位置處,等等。
字符串庫中的所有函數(shù)都在表 string
中。
它還將其設(shè)置為字符串元表的 __index
域。
因此,你可以以面向?qū)ο蟮男问绞褂米址瘮?shù)。
例如,string.byte(s,i)
可以寫成 s:byte(i)
。
字符串庫假定采用單字節(jié)字符編碼。
string.byte (s [, i [, j]])
s[i]
,
s[i+1]
, ... ,s[j]
的內(nèi)部數(shù)字編碼。
i
的默認(rèn)值是 1 ;
j
的默認(rèn)值是 i
。
這些索引以函數(shù) string.sub
的規(guī)則修正。
數(shù)字編碼沒有必要跨平臺。
string.char (···)
數(shù)字編碼沒有必要跨平臺。
string.dump (function [, strip])
返回包含有以二進(jìn)制方式表示的(一個 二進(jìn)制代碼塊 )指定函數(shù)的字符串。
之后可以用 load
調(diào)用這個字符串獲得
該函數(shù)的副本(但是綁定新的上值)。
如果 strip
為真值,
二進(jìn)制代碼塊不攜帶該函數(shù)的調(diào)試信息
(局部變量名,行號,等等。)。
帶上值的函數(shù)只保存上值的數(shù)目。 當(dāng)(再次)加載時,這些上值被更新為 nil 的實例。 (你可以使用調(diào)試庫按你需要的方式來序列化上值,并重載到函數(shù)中)
string.find (s, pattern [, init [, plain]])
查找第一個字符串 s
中匹配到的 pattern
(參見 §6.4.1)。
如果找到一個匹配,find
會返回 s
中關(guān)于它起始及終點位置的索引;
否則,返回 nil。
第三個可選數(shù)字參數(shù) init
指明從哪里開始搜索;
默認(rèn)值為 1 ,同時可以是負(fù)值。
第四個可選參數(shù) plain
為 true 時,
關(guān)閉模式匹配機制。
此時函數(shù)僅做直接的 “查找子串”的操作,
而 pattern
中沒有字符被看作魔法字符。
注意,如果給定了 plain
,就必須寫上 init
。
如果在模式中定義了捕獲,捕獲到的若干值也會在兩個索引之后返回。
string.format (formatstring, ···)
返回不定數(shù)量參數(shù)的格式化版本,
格式化串為第一個參數(shù)(必須是一個字符串)。
格式化字符串遵循 ISO C 函數(shù) sprintf
的規(guī)則。
不同點在于選項
*
, h
, L
, l
, n
,
p
不支持,
另外還增加了一個選項 q
。
q
選項將一個字符串格式化為兩個雙引號括起,對內(nèi)部字符做恰當(dāng)?shù)霓D(zhuǎn)義處理的字符串。
該字符串可以安全的被 Lua 解釋器讀回來。
例如,調(diào)用
string.format('%q', 'a string with "quotes" and \n new line')
會產(chǎn)生字符串:
"a string with \"quotes\" and \ new line"
選項
A
and a
(如果有的話),
E
, e
, f
,
G
, and g
都期待一個對應(yīng)的數(shù)字參數(shù)。
選項 c
, d
,
i
, o
, u
, X
, and x
則期待一個整數(shù)。
選項 q
期待一個字符串;
選項 s
期待一個沒有內(nèi)嵌零的字符串。
如果選項 s
對應(yīng)的參數(shù)不是字符串,它會用和
tostring
一致的規(guī)則轉(zhuǎn)換成字符串。
string.gmatch (s, pattern)
pattern
(參見 §6.4.1)
對 s
做匹配,并返回所有捕獲到的值。
如果 pattern
中沒有指定捕獲,則每次捕獲整個 pattern
。
下面這個例子會循環(huán)迭代字符串 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
對這個函數(shù)來說,模板前開始的 '^
' 不會當(dāng)成錨點。因為這樣會阻止迭代。
string.gsub (s, pattern, repl [, n])
s
中,所有的(或是在 n
給出時的前 n
個)
pattern
(參見
§6.4.1)都替換成 repl
,并返回其副本。
repl
可以是字符串、表、或函數(shù)。
gsub
還會在第二個返回值返回一共發(fā)生了多少次匹配。
gsub
這個名字來源于 Global SUBstitution 。
如果 repl
是一個字符串,那么把這個字符串作為替換品。
字符 %
是一個轉(zhuǎn)義符:
repl
中的所有形式為 %d
的串表示
第 d 個捕獲到的子串,d 可以是 1 到 9 。
串 %0
表示整個匹配。
串 %%
表示單個 %
。
如果 repl
是張表,每次匹配時都會用第一個捕獲物作為鍵去查這張表。
如果 repl
是個函數(shù),則在每次匹配發(fā)生時都會調(diào)用這個函數(shù)。
所有捕獲到的子串依次作為參數(shù)傳入。
任何情況下,模板中沒有設(shè)定捕獲都看成是捕獲整個模板。
如果表的查詢結(jié)果或函數(shù)的返回結(jié)果是一個字符串或是個數(shù)字, 都將其作為替換用串; 而在返回 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.3"} x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t) --> x="lua-5.3.tar.gz"
string.len (s)
""
的長度為 0 。
內(nèi)嵌零也統(tǒng)計在內(nèi),因此
"a\000bc\000"
的長度為 5 。
string.lower (s)
string.match (s, pattern [, init])
s
中找到第一個能用 pattern
(參見 §6.4.1)匹配到的部分。
如果能找到,match
返回其中的捕獲物;
否則返回 nil 。
如果 pattern
中未指定捕獲,
返回整個 pattern
捕獲到的串。
第三個可選數(shù)字參數(shù) init
指明從哪里開始搜索;
它默認(rèn)為 1 且可以是負(fù)數(shù)。
string.pack (fmt, v1, v2, ···)
返回一個打包了(即以二進(jìn)制形式序列化) v1
, v2
等值的二進(jìn)制字符串。
字符串 fmt
為打包格式(參見 §6.4.2)。
string.packsize (fmt)
返回以指定格式用 string.pack
打包的字符串的長度。
格式化字符串中不可以有變長選項 's
' 或 'z
'
(參見 §6.4.2)。
string.rep (s, n [, sep])
n
個字符串 s
以字符串 sep
為分割符連在一起的字符串。
默認(rèn)的 sep
值為空字符串(即沒有分割符)。
如果 n
不是正數(shù)則返回空串。
string.reverse (s)
s
的翻轉(zhuǎn)串。
string.sub (s, i [, j])
s
的子串,
該子串從 i
開始到 j
為止;
i
和 j
都可以為負(fù)數(shù)。
如果不給出 j
,就當(dāng)它是 -1
(和字符串長度相同)。
特別是,
調(diào)用 string.sub(s,1,j)
可以返回 s
的長度為 j
的前綴串,
而 string.sub(s, -i)
返回長度為 i
的后綴串。
如果在對負(fù)數(shù)索引轉(zhuǎn)義后 i
小于 1 的話,就修正回 1 。
如果 j
比字符串的長度還大,就修正為字符串長度。
如果在修正之后,i
大于 j
,
函數(shù)返回空串。
string.unpack (fmt, s [, pos])
返回以格式 fmt
(參見 §6.4.2)
打包在字符串 s
(參見 string.pack
)
中的值。
選項 pos
(默認(rèn)為 1 )標(biāo)記了從 s
中哪里開始讀起。
讀完所有的值后,函數(shù)返回 s
中第一個未讀字節(jié)的位置。
string.upper (s)
Lua 中的匹配模式直接用常規(guī)的字符串來描述。
它用于模式匹配函數(shù)
string.find
,
string.gmatch
,
string.gsub
,
string.match
。
這一節(jié)表述了這些字符串的語法及含義(即它能匹配到什么)。
字符類 用于表示一個字符集合。 下列組合可用于字符類:
^$()%.[]*+-?
中的一員)
表示字符 x 自身。
.
: (一個點)可表示任何字符。%a
: 表示任何字母。%c
: 表示任何控制字符。%d
: 表示任何數(shù)字。%g
: 表示任何除空白符外的可打印字符。%l
: 表示所有小寫字母。%p
: 表示所有標(biāo)點符號。%s
: 表示所有空白字符。%u
: 表示所有大寫字母。%w
: 表示所有字母及數(shù)字。%x
: 表示所有 16 進(jìn)制數(shù)字符號。%x
:
(這里的 x 是任意非字母或數(shù)字的字符)
表示字符 x。
這是對魔法字符轉(zhuǎn)義的標(biāo)準(zhǔn)方法。
所有非字母或數(shù)字的字符
(包括所有標(biāo)點,也包括非魔法字符)
都可以用前置一個 '%
' 放在模式串中表示自身。
[set]
:
表示 set 中所有字符的聯(lián)合。
可以以 '-
' 連接,升序書寫范圍兩端的字符來表示一個范圍的字符集。
上面提到的 %
x 形式也可以在 set 中使用
表示其中的一個元素。
其它出現(xiàn)在 set 中的字符則代表它們自己。
例如,[%w_]
(或 [_%w]
)
表示所有的字母數(shù)字加下劃線),
[0-7]
表示 8 進(jìn)制數(shù)字,
[0-7%l%-]
表示 8 進(jìn)制數(shù)字加小寫字母與 '-
' 字符。
交叉使用類和范圍的行為未定義。
因此,像 [%a-z]
或 [a-%%]
這樣的模式串沒有意義。
[^set]
:
表示 set 的補集,
其中 set 如上面的解釋。
所有單個字母表示的類別(%a
,%c
,等),
若將其字母改為大寫,均表示對應(yīng)的補集。
例如,%S
表示所有非空格的字符。
如何定義字母、空格、或是其他字符組取決于當(dāng)前的區(qū)域設(shè)置。
特別注意:[a-z]
未必等價于 %l
。
模式條目 可以是
*
',
將匹配零或多個該類的字符。
這個條目總是匹配盡可能長的串;
+
',
將匹配一或更多個該類的字符。
這個條目總是匹配盡可能長的串;
-
',
將匹配零或更多個該類的字符。
和 '*
' 不同,
這個條目總是匹配盡可能短的串;
?
',
將匹配零或一個該類的字符。
只要有可能,它會匹配一個;
%n
,
這里的 n 可以從 1 到 9;
這個條目匹配一個等于 n 號捕獲物(后面有描述)的子串。
%bxy
,
這里的 x 和 y 是兩個明確的字符;
這個條目匹配以 x 開始 y 結(jié)束,
且其中 x 和 y 保持 平衡 的字符串。
意思是,如果從左到右讀這個字符串,對每次讀到一個
x 就 +1 ,讀到一個 y 就 -1,
最終結(jié)束處的那個 y 是第一個記數(shù)到 0 的 y。
舉個例子,條目 %b()
可以匹配到括號平衡的表達(dá)式。
%f[set]
,
指 邊境模式;
這個條目會匹配到一個位于 set 內(nèi)某個字符之前的一個空串,
且這個位置的前一個字符不屬于 set 。
集合 set 的含義如前面所述。
匹配出的那個空串之開始和結(jié)束點的計算就看成該處有個字符
'\0
' 一樣。
模式 指一個模式條目的序列。
在模式最前面加上符號 '^
' 將錨定從字符串的開始處做匹配。
在模式最后面加上符號 '$
' 將使匹配過程錨定到字符串的結(jié)尾。
如果 '^
' 和 '$
' 出現(xiàn)在其它位置,它們均沒有特殊含義,只表示自身。
模式可以在內(nèi)部用小括號括起一個子模式;
這些子模式被稱為 捕獲物。
當(dāng)匹配成功時,由 捕獲物 匹配到的字符串中的子串被保存起來用于未來的用途。
捕獲物以它們左括號的次序來編號。
例如,對于模式 "(a*(.)%w(%s*))"
,
字符串中匹配到 "a*(.)%w(%s*)"
的部分保存在第一個捕獲物中
(因此是編號 1 );
由 ".
" 匹配到的字符是 2 號捕獲物,
匹配到 "%s*
" 的那部分是 3 號。
作為一個特例,空的捕獲 ()
將捕獲到當(dāng)前字符串的位置(它是一個數(shù)字)。
例如,如果將模式 "()aa()"
作用到字符串
"flaaap"
上,將產(chǎn)生兩個捕獲物:
3 和 5 。
用于 string.pack
,
string.packsize
,
string.unpack
的第一個參數(shù)。
它是一個描述了需要創(chuàng)建或讀取的結(jié)構(gòu)之布局。
格式串是由轉(zhuǎn)換選項構(gòu)成的序列。 這些轉(zhuǎn)換選項列在后面:
<
: 設(shè)為小端編碼>
: 設(shè)為大端編碼=
: 大小端遵循本地設(shè)置![n]
: 將最大對齊數(shù)設(shè)為 n
(默認(rèn)遵循本地對齊設(shè)置)b
: 一個有符號字節(jié) (char
)B
: 一個無符號字節(jié) (char
)h
: 一個有符號 short
(本地大?。?/li>
H
: 一個無符號 short
(本地大?。?/li>
l
: 一個有符號 long
(本地大小)L
: 一個無符號 long
(本地大?。?/li>
j
: 一個 lua_Integer
J
: 一個 lua_Unsigned
T
: 一個 size_t
(本地大小)i[n]
: 一個 n
字節(jié)長(默認(rèn)為本地大?。┑挠蟹?int
I[n]
: 一個 n
字節(jié)長(默認(rèn)為本地大?。┑臒o符號 int
f
: 一個 float
(本地大小)d
: 一個 double
(本地大?。?/li>
n
: 一個 lua_Number
cn
: n
字節(jié)固定長度的字符串z
: 零結(jié)尾的字符串s[n]
: 長度加內(nèi)容的字符串,其長度編碼為一個 n
字節(jié)(默認(rèn)是個 size_t
) 長的無符號整數(shù)。x
: 一個字節(jié)的填充Xop
: 按選項 op
的方式對齊(忽略它的其它方面)的一個空條目
': (空格)忽略
( "[n]
" 表示一個可選的整數(shù)。)
除填充、空格、配置項(選項 "xX <=>!
")外,
每個選項都關(guān)聯(lián)一個參數(shù)(對于 string.pack
)
或結(jié)果(對于 string.unpack
)。
對于選項 "!n
", "sn
", "in
", "In
",
n
可以是 1 到 16 間的整數(shù)。
所有的整數(shù)選項都將做溢出檢查;
string.pack
檢查提供的值是否能用指定的字長表示;
string.unpack
檢查讀出的值能否置入 Lua 整數(shù)中。
任何格式串都假設(shè)有一個 "!1=
" 前綴,
即最大對齊為 1 (無對齊)且采用本地大小端設(shè)置。
對齊行為按如下規(guī)則工作:
對每個選項,格式化時都會填充一些字節(jié)直到數(shù)據(jù)從一個特定偏移處開始,
這個位置是該選項的大小和最大對齊數(shù)中較小的那個數(shù)的倍數(shù);
這個較小值必須是 2 個整數(shù)次方。
選項 "c
" 及 "z
" 不做對齊處理;
選項 "s
" 對對齊遵循其開頭的整數(shù)。
string.pack
用零去填充
(string.unpack
則忽略它)。
這個庫提供了對 UTF-8 編碼的基礎(chǔ)支持。
所有的函數(shù)都放在表 utf8
中。
此庫不提供除編碼處理之外的任何 Unicode 支持。
所有需要了解字符含義的操作,比如字符分類,都不在此范疇。
除非另有說明, 當(dāng)一個函數(shù)需要一個字節(jié)位置的參數(shù)時, 都假定這個位置要么從字節(jié)序列的開始計算, 要么從字符串長度加一的位置算。 和字符串庫一樣,負(fù)的索引從字符串末尾計起。
utf8.char (···)
utf8.charpattern
[\0-\x7F\xC2-\xF4][\x80-\xBF]*
"
(參見 §6.4.1)。
它假定處理的對象是一個合法的 UTF-8 字符串。
utf8.codes (s)
返回一系列的值,可以讓
for p, c in utf8.codes(s) do body end
迭代出字符串 s
中所有的字符。
這里的 p
是位置(按字節(jié)數(shù))而 c
是每個字符的編號。
如果處理到一個不合法的字節(jié)序列,將拋出一個錯誤。
utf8.codepoint (s [, i [, j]])
s
中
從位置 i
到 j
間(包括兩端)
所有字符的編號。
默認(rèn)的 i
為 1 ,默認(rèn)的 j
為 i
。
如果碰上不合法的字節(jié)序列,拋出一個錯誤。
utf8.len (s [, i [, j]])
s
中
從位置 i
到 j
間 (包括兩端)
UTF-8 字符的個數(shù)。
默認(rèn)的 i
為 1 ,默認(rèn)的 j
為 -1 。
如果它找到任何不合法的字節(jié)序列,
返回假值加上第一個不合法字節(jié)的位置。
utf8.offset (s, n [, i])
s
中的第 n
個字符的開始位置(按字節(jié)數(shù))
(從位置 i
處開始統(tǒng)計)。
負(fù) n
則取在位置 i
前的字符。
當(dāng) n
是非負(fù)數(shù)時,默認(rèn)的 i
是 1,
否則默認(rèn)為 #s + 1
。
因此,utf8.offset(s, -n)
取字符串的倒數(shù)第
n
個字符的位置。
如果指定的字符不在其中或在結(jié)束點之后,函數(shù)返回 nil。
作為特例,當(dāng) n
等于 0 時,
此函數(shù)返回含有 s
第 i
字節(jié)的那個字符的開始位置。
這個函數(shù)假定 s
是一個合法的 UTF-8 字符串。
這個庫提供了表處理的通用函數(shù)。
所有函數(shù)都放在表 table
中。
記住,無論何時,若一個操作需要取表的長度,
這張表必須是一個真序列,或是擁有 __len
元方法
(參見 §3.4.7 )。
所有的函數(shù)都忽略傳入?yún)?shù)的那張表中的非數(shù)字鍵。
table.concat (list [, sep [, i [, j]]])
提供一個列表,其所有元素都是字符串或數(shù)字,返回字符串
list[i]..sep..list[i+1] ··· sep..list[j]
。
sep
的默認(rèn)值是空串,
i
的默認(rèn)值是 1 ,
j
的默認(rèn)值是 #list
。
如果 i
比 j
大,返回空串。
table.insert (list, [pos,] value)
在 list
的位置 pos
處插入元素 value
,
并后移元素 list[pos], list[pos+1], ···, list[#list]
。
pos
的默認(rèn)值為 #list+1
,
因此調(diào)用 table.insert(t,x)
會將 x
插在列表 t
的末尾。
table.move (a1, f, e, t [,a2])
將元素從表 a1
移到表 a2
。
這個函數(shù)做了次等價于后面這個多重賦值的等價操作:
a2[t],··· = a1[f],···,a1[e]
。
a2
的默認(rèn)值為 a1
。
目標(biāo)區(qū)間可以和源區(qū)間重疊。
索引 f
必須是正數(shù)。
table.pack (···)
返回用所有參數(shù)以鍵 1,2, 等填充的新表,
并將 "n
" 這個域設(shè)為參數(shù)的總數(shù)。
注意這張返回的表不一定是一個序列。
table.remove (list [, pos])
移除 list
中 pos
位置上的元素,并返回這個被移除的值。
當(dāng) pos
是在 1 到 #list
之間的整數(shù)時,
它向前移動元素 list[pos+1], list[pos+2], ···, list[#list]
并刪除元素 list[#list]
;
索引 pos
可以是 #list + 1
,或在 #list
為 0 時可以是 0 ;
在這些情況下,函數(shù)刪除元素 list[pos]
。
pos
默認(rèn)為 #list
,
因此調(diào)用 table.remove(l)
將移除表 l
的最后一個元素。
table.sort (list [, comp])
在表內(nèi)從 list[1]
到 list[#list]
原地
對其間元素按指定次序排序。
如果提供了 comp
,
它必須是一個可以接收兩個列表內(nèi)元素為參數(shù)的函數(shù)。
當(dāng)?shù)谝粋€元素需要排在第二個元素之前時,返回真
(因此 not comp(list[i+1],list[i])
在排序結(jié)束后將為真)。
如果沒有提供 comp
,
將使用標(biāo)準(zhǔn) Lua 操作 <
作為替代品。
排序算法并不穩(wěn)定; 即當(dāng)兩個元素次序相等時,它們在排序后的相對位置可能會改變。
table.unpack (list [, i [, j]])
返回列表中的元素。 這個函數(shù)等價于
return list[i], list[i+1], ···, list[j]
i
默認(rèn)為 1 ,j
默認(rèn)為 #list
。
這個庫提供了基本的數(shù)學(xué)函數(shù)。
所以函數(shù)都放在表 math
中。
注解有 "integer/float
" 的函數(shù)會對整數(shù)參數(shù)返回整數(shù)結(jié)果,
對浮點(或混合)參數(shù)返回浮點結(jié)果。
圓整函數(shù)(math.ceil
, math.floor
, math.modf
)
在結(jié)果在整數(shù)范圍內(nèi)時返回整數(shù),否則返回浮點數(shù)。
math.abs (x)
返回 x
的絕對值。(integer/float)
math.acos (x)
返回 x
的反余弦值(用弧度表示)。
math.asin (x)
返回 x
的反正弦值(用弧度表示)。
math.atan (y [, x])
返回 y/x
的反正切值(用弧度表示)。
它會使用兩個參數(shù)的符號來找到結(jié)果落在哪個象限中。
(即使 x
為零時,也可以正確的處理。)
默認(rèn)的 x
是 1 ,
因此調(diào)用 math.atan(y)
將返回
y
的反正切值。
math.ceil (x)
返回不小于 x
的最小整數(shù)值。
math.cos (x)
返回 x
的余弦(假定參數(shù)是弧度)。
math.deg (x)
將角 x
從弧度轉(zhuǎn)換為角度。
math.exp (x)
返回 ex 的值
(e
為自然對數(shù)的底)。
math.floor (x)
返回不大于 x
的最大整數(shù)值。
math.fmod (x, y)
返回 x
除以 y
,將商向零圓整后的余數(shù)。
(integer/float)
math.huge
浮點數(shù) HUGE_VAL
,
這個數(shù)比任何數(shù)字值都大。
math.log (x [, base])
返回以指定底的 x
的對數(shù)。
默認(rèn)的 base
是 e
(因此此函數(shù)返回 x
的自然對數(shù))。
math.max (x, ···)
返回參數(shù)中最大的值,
大小由 Lua 操作 <
決定。
(integer/float)
math.maxinteger
math.min (x, ···)
返回參數(shù)中最小的值,
大小由 Lua 操作 <
決定。
(integer/float)
math.mininteger
math.modf (x)
返回 x
的整數(shù)部分和小數(shù)部分。
第二個結(jié)果一定是浮點數(shù)。
math.pi
π 的值。
math.rad (x)
將角 x
從角度轉(zhuǎn)換為弧度。
math.random ([m [, n]])
當(dāng)不帶參數(shù)調(diào)用時,
返回一個 [0,1) 區(qū)間內(nèi)一致分布的浮點偽隨機數(shù)。
當(dāng)以兩個整數(shù) m
與 n
調(diào)用時,
math.random
返回一個 [m, n] 區(qū)間
內(nèi)一致分布的整數(shù)偽隨機數(shù)。
(值 n-m 不能是負(fù)數(shù),且必須在 Lua 整數(shù)的表示范圍內(nèi)。)
調(diào)用 math.random(n)
等價于 math.random(1,n)
。
這個函數(shù)是對 C 提供的位隨機數(shù)函數(shù)的封裝。 對其統(tǒng)計屬性不作擔(dān)保。
math.randomseed (x)
把 x
設(shè)為偽隨機數(shù)發(fā)生器的“種子”:
相同的種子產(chǎn)生相同的隨機數(shù)列。
math.sin (x)
返回 x
的正弦值(假定參數(shù)是弧度)。
math.sqrt (x)
返回 x
的平方根。
(你也可以使用乘方 x^0.5
來計算這個值。)
math.tan (x)
返回 x
的正切值(假定參數(shù)是弧度)。
math.tointeger (x)
如果 x
可以轉(zhuǎn)換為一個整數(shù),
返回該整數(shù)。
否則返回 nil。
math.type (x)
如果 x
是整數(shù),返回 "integer
",
如果它是浮點數(shù),返回 "float
",
如果 x
不是數(shù)字,返回 nil。
math.ult (m, n)
如果整數(shù) m
和 n
以無符號整數(shù)形式比較,
m
在 n
之下,返回布爾真否則返回假。
I/O 庫提供了兩套不同風(fēng)格的文件處理接口。 第一種風(fēng)格使用隱式的文件句柄; 它提供設(shè)置默認(rèn)輸入文件及默認(rèn)輸出文件的操作, 所有的輸入輸出操作都針對這些默認(rèn)文件。 第二種風(fēng)格使用顯式的文件句柄。
當(dāng)使用隱式文件句柄時,
所有的操作都由表 io
提供。
若使用顯式文件句柄,
io.open
會返回一個文件句柄,且所有的操作都由該文件句柄的方法來提供。
表 io
中也提供了三個
和 C 中含義相同的預(yù)定義文件句柄:
io.stdin
, io.stdout
, 以及 io.stderr
。
I/O 庫永遠(yuǎn)不會關(guān)閉這些文件。
除非另有說明,
I/O 函數(shù)在出錯時都返回 nil
(第二個返回值為錯誤消息,第三個返回值為系統(tǒng)相關(guān)的錯誤碼)。
成功時返回與 nil 不同的值。
在非 POSIX 系統(tǒng)上,
根據(jù)錯誤碼取出錯誤消息的過程可能并非線程安全的,
因為這使用了 C 的全局變量 errno
。
io.close ([file])
等價于 file:close()
。
不給出 file
時將關(guān)閉默認(rèn)輸出文件。
io.flush ()
等價于 io.output():flush()
。
io.input ([file])
用文件名調(diào)用它時,(以文本模式)來打開該名字的文件, 并將文件句柄設(shè)為默認(rèn)輸入文件。 如果用文件句柄去調(diào)用它, 就簡單的將該句柄設(shè)為默認(rèn)輸入文件。 如果調(diào)用時不傳參數(shù),它返回當(dāng)前的默認(rèn)輸入文件。
在出錯的情況下,函數(shù)拋出錯誤而不是返回錯誤碼。
io.lines ([filename ···])
以讀模式打開指定的文件名并返回一個迭代函數(shù)。
此迭代函數(shù)的工作方式和用一個已打開的文件去調(diào)用
file:lines(···)
得到的迭代器相同。
當(dāng)?shù)瘮?shù)檢測到文件結(jié)束,
它不返回值(讓循環(huán)結(jié)束)并自動關(guān)閉文件。
調(diào)用 io.lines()
(不傳文件名)
等價于 io.input():lines("*l")
;
即,它將按行迭代標(biāo)準(zhǔn)輸入文件。
在此情況下,循環(huán)結(jié)束后它不會關(guān)閉文件。
在出錯的情況下,函數(shù)拋出錯誤而不是返回錯誤碼。
io.open (filename [, mode])
這個函數(shù)用字符串 mode
指定的模式打開一個文件。
返回新的文件句柄。
當(dāng)出錯時,返回 nil 加錯誤消息。
mode
字符串可以是下列任意值:
r
": 讀模式(默認(rèn));w
": 寫模式;a
": 追加模式;r+
": 更新模式,所有之前的數(shù)據(jù)都保留;w+
": 更新模式,所有之前的數(shù)據(jù)都刪除;a+
": 追加更新模式,所有之前的數(shù)據(jù)都保留,只允許在文件尾部做寫入。
mode
字符串可以在最后加一個 'b
' ,
這會在某些系統(tǒng)上以二進(jìn)制方式打開文件。
io.output ([file])
類似于 io.input
。
不過都針對默認(rèn)輸出文件操作。
io.popen (prog [, mode])
這個函數(shù)和系統(tǒng)有關(guān),不是所有的平臺都提供。
用一個分離進(jìn)程開啟程序 prog
,
返回的文件句柄可用于從這個程序中讀取數(shù)據(jù)
(如果 mode
為 "r"
,這是默認(rèn)值)
或是向這個程序?qū)懭胼斎耄ó?dāng)
mode
為 "w"
時)。
io.read (···)
等價于 io.input():read(···)
。
io.tmpfile ()
如果成功,返回一個臨時文件的句柄。 這個文件以更新模式打開,在程序結(jié)束時會自動刪除。
io.type (obj)
檢查 obj
是否是合法的文件句柄。
如果 obj
它是一個打開的文件句柄,返回字符串 "file"
。
如果 obj
是一個關(guān)閉的文件句柄,返回字符串 "closed file"
。
如果 obj
不是文件句柄,返回 nil 。
io.write (···)
等價于 io.output():write(···)
。
file:close ()
關(guān)閉 file
。
注意,文件在句柄被垃圾回收時會自動關(guān)閉,
但是多久以后發(fā)生,時間不可預(yù)期的。
當(dāng)關(guān)閉用 io.popen
創(chuàng)建出來的文件句柄時,
file:close
返回 os.execute
會返回的一樣的值。
file:flush ()
將寫入的數(shù)據(jù)保存到 file
中。
file:lines (···)
返回一個迭代器函數(shù),
每次調(diào)用迭代器時,都從文件中按指定格式讀數(shù)據(jù)。
如果沒有指定格式,使用默認(rèn)值 "l
" 。
看一個例子
for c in file:lines(1) do body end
會從文件當(dāng)前位置開始,中不斷讀出字符。
和 io.lines
不同,
這個函數(shù)在循環(huán)結(jié)束后不會關(guān)閉文件。
在出錯的情況下,函數(shù)拋出錯誤而不是返回錯誤碼。
file:read (···)
讀文件 file
,
指定的格式?jīng)Q定了要讀什么。
對于每種格式,函數(shù)返回讀出的字符對應(yīng)的字符串或數(shù)字。
若不能以該格式對應(yīng)讀出數(shù)據(jù)則返回 nil。
(對于最后這種情況,
函數(shù)不會讀出后續(xù)的格式。)
當(dāng)調(diào)用時不傳格式,它會使用默認(rèn)格式讀下一行(見下面描述)。
提供的格式有
n
":
讀取一個數(shù)字,根據(jù) Lua 的轉(zhuǎn)換文法,可能返回浮點數(shù)或整數(shù)。
(數(shù)字可以有前置或后置的空格,以及符號。)
只要能構(gòu)成合法的數(shù)字,這個格式總是去讀盡量長的串;
如果讀出來的前綴無法構(gòu)成合法的數(shù)字
(比如空串,"0x
" 或 "3.4e-
"),
就中止函數(shù)運行,返回 nil。
a
":
從當(dāng)前位置開始讀取整個文件。
如果已在文件末尾,返回空串。
l
":
讀取一行并忽略行結(jié)束標(biāo)記。
當(dāng)在文件末尾時,返回 nil
這是默認(rèn)格式。
L
":
讀取一行并保留行結(jié)束標(biāo)記(如果有的話),
當(dāng)在文件末尾時,返回 nil。
number
為零,
它什么也不讀,返回一個空串。
當(dāng)在文件末尾時,返回 nil。
格式 "l
" 和 "L
" 只能用于文本文件。
file:seek ([whence [, offset]])
設(shè)置及獲取基于文件開頭處計算出的位置。
設(shè)置的位置由 offset
和
whence
字符串 whence
指定的基點決定。基點可以是:
set
": 基點為 0 (文件開頭);cur
": 基點為當(dāng)前位置;end
": 基點為文件尾;
當(dāng) seek
成功時,返回最終從文件開頭計算起的文件的位置。
當(dāng) seek
失敗時,返回 nil 加上一個錯誤描述字符串。
whence
的默認(rèn)值是 "cur"
,
offset
默認(rèn)為 0 。
因此,調(diào)用 file:seek()
可以返回文件當(dāng)前位置,并不改變它;
調(diào)用 file:seek("set")
將位置設(shè)為文件開頭(并返回 0);
調(diào)用 file:seek("end")
將位置設(shè)到文件末尾,并返回文件大小。
file:setvbuf (mode [, size])
設(shè)置輸出文件的緩沖模式。 有三種模式:
no
":
不緩沖;輸出操作立刻生效。
full
":
完全緩沖;只有在緩存滿或當(dāng)你顯式的對文件調(diào)用
flush
(參見 io.flush
)
時才真正做輸出操作。
line
":
行緩沖;
輸出將緩沖到每次換行前,
對于某些特殊文件(例如終端設(shè)備)緩沖到任何輸入前。
對于后兩種情況,size
以字節(jié)數(shù)為單位
指定緩沖區(qū)大小。
默認(rèn)會有一個恰當(dāng)?shù)拇笮 ?
file:write (···)
將參數(shù)的值逐個寫入 file
。
參數(shù)必須是字符串或數(shù)字。
成功時,函數(shù)返回 file
。
否則返回 nil 加錯誤描述字符串。
這個庫都通過表 os
實現(xiàn)。
os.clock ()
返回程序使用的按秒計 CPU 時間的近似值。
os.date ([format [, time]])
返回一個包含日期及時刻的字符串或表。
格式化方法取決于所給字符串 format
。
如果提供了 time
參數(shù),
格式化這個時間
(這個值的含義參見 os.time
函數(shù))。
否則,date
格式化當(dāng)前時間。
如果 format
以 '!
' 打頭,
日期以協(xié)調(diào)世界時格式化。
在這個可選字符項之后,
如果 format
為字符串 "*t
",
date
返回有后續(xù)域的表:
year
(四位數(shù)字),month
(1–12),day
(1–31),
hour
(0–23),min
(0–59),sec
(0–61),
wday
(星期幾,星期天為 1 ),
yday
(當(dāng)年的第幾天),
以及 isdst
(夏令時標(biāo)記,一個布爾量)。
對于最后一個域,如果該信息不提供的話就不存在。
如果 format
并非 "*t
",
date
以字符串形式返回,
格式化方法遵循 ISO C 函數(shù) strftime
的規(guī)則。
如果不傳參數(shù)調(diào)用,
date
返回一個合理的日期時間串,
格式取決于宿主程序以及當(dāng)前的區(qū)域設(shè)置
(即,os.date()
等價于 os.date("%c")
)。
在非 POSIX 系統(tǒng)上,
由于這個函數(shù)依賴 C 函數(shù) gmtime
和 localtime
,
它可能并非線程安全的。
os.difftime (t2, t1)
返回以秒計算的時刻 t1
到 t2
的差值。
(這里的時刻是由 os.time
返回的值)。
在 POSIX,Windows,和其它一些系統(tǒng)中,這個值就等于
t2
-t1
。
os.execute ([command])
這個函數(shù)等價于 ISO C 函數(shù) system
。
它調(diào)用系統(tǒng)解釋器執(zhí)行 command
。
如果命令成功運行完畢,第一個返回值就是 true,
否則是 nil。
在第一個返回值之后,函數(shù)返回一個字符串加一個數(shù)字。如下:
exit
":
命令正常結(jié)束;
接下來的數(shù)字是命令的退出狀態(tài)碼。
signal
":
命令被信號打斷;
接下來的數(shù)字是打斷該命令的信號。
如果不帶參數(shù)調(diào)用,
os.execute
在系統(tǒng)解釋器存在的時候返回真。
os.exit ([code [, close]])
調(diào)用 ISO C 函數(shù) exit
終止宿主程序。
如果 code
為 true,
返回的狀態(tài)碼是 EXIT_SUCCESS
;
如果 code
為 false,
返回的狀態(tài)碼是 EXIT_FAILURE
;
如果 code
是一個數(shù)字,
返回的狀態(tài)碼就是這個數(shù)字。
code
的默認(rèn)值為 true。
如果第二個可選參數(shù) close
為真,
在退出前關(guān)閉 Lua 狀態(tài)機。
os.getenv (varname)
返回進(jìn)程環(huán)境變量 varname
的值,
如果該變量未定義,返回 nil 。
os.remove (filename)
刪除指定名字的文件(在 POSIX 系統(tǒng)上可以是一個空目錄) 如果函數(shù)失敗,返回 nil 加一個錯誤描述串及出錯碼。
os.rename (oldname, newname)
將名字為 oldname
的文件或目錄更名為 newname
。
如果函數(shù)失敗,返回 nil
加一個錯誤描述串及出錯碼。
os.setlocale (locale [, category])
設(shè)置程序的當(dāng)前區(qū)域。
locale
是一個區(qū)域設(shè)置的系統(tǒng)相關(guān)字符串;
category
是一個描述有改變哪個分類的可選字符串:
"all"
,"collate"
, "ctype"
,
"monetary"
, "numeric"
, 或 "time"
;
默認(rèn)的分類為 "all"
。
此函數(shù)返回新區(qū)域的名字。
如果請求未被獲準(zhǔn),返回 nil 。
當(dāng) locale
是一個空串,
當(dāng)前區(qū)域被設(shè)置為一個在實現(xiàn)中定義好的本地區(qū)域。
當(dāng) locale
為字符串 "C
",
當(dāng)前區(qū)域被設(shè)置為標(biāo)準(zhǔn) C 區(qū)域。
當(dāng)?shù)谝粋€參數(shù)為 nil 時, 此函數(shù)僅返回當(dāng)前區(qū)域指定分類的名字。
由于這個函數(shù)依賴 C 函數(shù) setlocale
,
它可能并非線程安全的。
os.time ([table])
當(dāng)不傳參數(shù)時,返回當(dāng)前時刻。
如果傳入一張表,就返回由這張表表示的時刻。
這張表必須包含域 year
,month
,及 day
;
可以包含有 hour
(默認(rèn)為 12 ),
min
(默認(rèn)為 0),
sec
(默認(rèn)為 0),以及 isdst
(默認(rèn)為 nil)。
關(guān)于這些域的詳細(xì)描述,參見 os.date
函數(shù)。
返回值是一個含義由你的系統(tǒng)決定的數(shù)字。
在 POSIX,Windows,和其它一些系統(tǒng)中,
這個數(shù)字統(tǒng)計了從指定時間("epoch")開始經(jīng)歷的秒數(shù)。
對于另外的系統(tǒng),其含義未定義,
你只能把 time
的返回數(shù)字用于
os.date
和 os.difftime
的參數(shù)。
os.tmpname ()
返回一個可用于臨時文件的文件名字符串。 這個文件在使用前必須顯式打開,不再使用時需要顯式刪除。
在 POSIX 系統(tǒng)上, 這個函數(shù)會以此文件名創(chuàng)建一個文件以回避安全風(fēng)險。 (別人可能未經(jīng)允許在獲取到這個文件名到創(chuàng)建該文件之間的時刻創(chuàng)建此文件。) 你依舊需要在使用它的時候先打開,并最后刪除(即使你沒使用到)。
只有有可能,你更應(yīng)該使用
io.tmpfile
,
因為該文件可以在程序結(jié)束時自動刪除。
這個庫提供了 Lua 程序調(diào)試接口(§4.9)的功能。 其中一些函數(shù)違反了 Lua 代碼的基本假定 (例如,不會從函數(shù)之外訪問函數(shù)的局部變量; 用戶數(shù)據(jù)的元表不會被 Lua 代碼修改; Lua 程序不會崩潰), 因此它們有可能危害到其它代碼的安全性。 此外,庫里的一些函數(shù)可能運行的很慢。
這個庫里的所有函數(shù)都提供在表 debug
內(nèi)。
所有操作線程的函數(shù),可選的第一個參數(shù)都是針對的線程。
默認(rèn)值永遠(yuǎn)是當(dāng)前線程。
debug.debug ()
進(jìn)入一個用戶交互模式,運行用戶輸入的每個字符串。
使用簡單的命令以及其它調(diào)試設(shè)置,用戶可以檢閱全局變量和局部變量,
改變變量的值,計算一些表達(dá)式,等等。
輸入一行僅包含 cont
的字符串將結(jié)束這個函數(shù),
這樣調(diào)用者就可以繼續(xù)向下運行。
注意,debug.debug
輸入的命令在文法上并沒有內(nèi)嵌到任何函數(shù)中,
因此不能直接去訪問局部變量。
debug.gethook ([thread])
返回三個表示線程鉤子設(shè)置的值:
當(dāng)前鉤子函數(shù),當(dāng)前鉤子掩碼,當(dāng)前鉤子計數(shù)
(debug.sethook
設(shè)置的那些)。
debug.getinfo ([thread,] f [, what])
返回關(guān)于一個函數(shù)信息的表。
你可以直接提供該函數(shù),
也可以用一個數(shù)字 f
表示該函數(shù)。
數(shù)字 f
表示運行在指定線程的調(diào)用棧對應(yīng)層次上的函數(shù):
0 層表示當(dāng)前函數(shù)(getinfo
自身);
1 層表示調(diào)用 getinfo
的函數(shù)
(除非是尾調(diào)用,這種情況不計入棧);等等。
如果 f
是一個比活動函數(shù)數(shù)量還大的數(shù)字,
getinfo
返回 nil。
只有字符串 what
中有描述要填充哪些項,
返回的表可以包含 lua_getinfo
能返回的所有項。
what
默認(rèn)是返回提供的除合法行號表外的所有信息。
對于選項 'f
' ,會在可能的情況下,增加
func
域保存函數(shù)自身。
對于選項 'L
' ,會在可能的情況下,增加
activelines
域保存合法行號表。
例如,表達(dá)式 debug.getinfo(1,"n")
返回帶有當(dāng)前函數(shù)名字信息的表(如果找的到名字的話),
表達(dá)式 debug.getinfo(print)
返回關(guān)于 print
函數(shù)的
包含有所有能提供信息的表。
debug.getlocal ([thread,] f, local)
此函數(shù)返回在棧的 f
層處函數(shù)的索引為 local
的局部變量
的名字和值。
這個函數(shù)不僅用于訪問顯式定義的局部變量,也包括形參、臨時變量等。
第一個形參或是定義的第一個局部變量的索引為 1 ,
然后遵循在代碼中定義次序,以次類推。
其中只計算函數(shù)當(dāng)前作用域的活動變量。
負(fù)索引指可變參數(shù);
-1 指第一個可變參數(shù)。
如果該索引處沒有變量,函數(shù)返回 nil。
若指定的層次越界,拋出錯誤。
(你可以調(diào)用 debug.getinfo
來檢查層次是否合法。)
以 '(
' (開括號)打頭的變量名表示沒有名字的變量
(比如是循環(huán)控制用到的控制變量,
或是去除了調(diào)試信息的代碼塊)。
參數(shù) f
也可以是一個函數(shù)。
這種情況下,getlocal
僅返回函數(shù)形參的名字。
debug.getmetatable (value)
返回給定 value
的元表。
若其沒有元表則返回 nil 。
debug.getregistry ()
返回注冊表(參見 §4.5)。
debug.getupvalue (f, up)
此函數(shù)返回函數(shù) f
的第 up
個上值的名字和值。
如果該函數(shù)沒有那個上值,返回 nil 。
以 '(
' (開括號)打頭的變量名表示沒有名字的變量
(去除了調(diào)試信息的代碼塊)。
debug.getuservalue (u)
返回關(guān)聯(lián)在 u
上的 Lua 值。
如果 u
并非用戶數(shù)據(jù),返回 nil。
debug.sethook ([thread,] hook, mask [, count])
將一個函數(shù)作為鉤子函數(shù)設(shè)入。
字符串 mask
以及數(shù)字 count
決定了鉤子將在何時調(diào)用。
掩碼是由下列字符組合成的字符串,每個字符有其含義:
c
': 每當(dāng) Lua 調(diào)用一個函數(shù)時,調(diào)用鉤子;r
': 每當(dāng) Lua 從一個函數(shù)內(nèi)返回時,調(diào)用鉤子;l
': 每當(dāng) Lua 進(jìn)入新的一行時,調(diào)用鉤子。
此外,
傳入一個不為零的 count
,
鉤子將在每運行 count
條指令時調(diào)用。
如果不傳入?yún)?shù),
debug.sethook
關(guān)閉鉤子。
當(dāng)鉤子被調(diào)用時,
第一個參數(shù)是觸發(fā)這次調(diào)用的事件:
"call"
(或 "tail call"
),
"return"
,
"line"
, "count"
。
對于行事件,
鉤子的第二個參數(shù)是新的行號。
在鉤子內(nèi),你可以調(diào)用 getinfo
,指定第 2 層,
來獲得正在運行的函數(shù)的詳細(xì)信息
(0 層指 getinfo
函數(shù),
1 層指鉤子函數(shù))。
debug.setlocal ([thread,] level, local, value)
這個函數(shù)將 value
賦給
棧上第 level
層函數(shù)的第 local
個局部變量。
如果沒有那個變量,函數(shù)返回 nil 。
如果 level
越界,拋出一個錯誤。
(你可以調(diào)用 debug.getinfo
來檢查層次是否合法。)
否則,它返回局部變量的名字。
關(guān)于變量索引和名字,參見 debug.getlocal
。
debug.setmetatable (value, table)
將 value
的元表設(shè)為 table
(可以是 nil)。
返回 value
。
debug.setupvalue (f, up, value)
這個函數(shù)將 value
設(shè)為函數(shù) f
的第
up
個上值。
如果函數(shù)沒有那個上值,返回 nil
否則,返回該上值的名字。
debug.setuservalue (udata, value)
將 value
設(shè)為 udata
的關(guān)聯(lián)值。
udata
必須是一個完全用戶數(shù)據(jù)。
返回 udata
。
debug.traceback ([thread,] [message [, level]])
如果 message
有,且不是字符串或 nil,
函數(shù)不做任何處理直接返回 message
。
否則,它返回調(diào)用棧的棧回溯信息。
字符串可選項 message
被添加在?;厮菪畔⒌拈_頭。
數(shù)字可選項 level
指明從棧的哪一層開始回溯
(默認(rèn)為 1 ,即調(diào)用 traceback
的那里)。
debug.upvalueid (f, n)
返回指定函數(shù)第 n
個上值的唯一標(biāo)識符(一個輕量用戶數(shù)據(jù))。
這個唯一標(biāo)識符可以讓程序檢查兩個不同的閉包是否共享了上值。 若 Lua 閉包之間共享的是同一個上值 (即指向一個外部局部變量),會返回相同的標(biāo)識符。
debug.upvaluejoin (f1, n1, f2, n2)
讓 Lua 閉包 f1
的第 n1
個上值
引用 Lua 閉包 f2
的第 n2
個上值。
雖然 Lua 被設(shè)計成一門擴(kuò)展式語言,用于嵌入一個宿主程序。
但經(jīng)常也會被當(dāng)成獨立語言使用。
獨立版的 Lua 語言解釋器隨標(biāo)準(zhǔn)包發(fā)布,就叫 lua
。
獨立版解釋器保留了所有的標(biāo)準(zhǔn)庫及調(diào)試庫。
其命令行用法為:
lua [options] [script [args]]
選項有:
-e stat
: 執(zhí)行一段字符串 stat ;-l mod
: “請求模塊” mod ;-i
: 在運行完 腳本 后進(jìn)入交互模式;-v
: 打印版本信息;-E
: 忽略環(huán)境變量;--
: 中止對后面選項的處理;-
: 把 stdin
當(dāng)作一個文件運行,并中止對后面選項的處理。
在處理完選項后,lua
運行指定的 腳本。
如果不帶參數(shù)調(diào)用,
在標(biāo)準(zhǔn)輸入(stdin
)是終端時,lua
的行為和 lua -v -i
相同。
否則相當(dāng)于 lua -
。
如果調(diào)用時不帶選項 -E
,
解釋器會在運行任何參數(shù)前,檢查環(huán)境變量 LUA_INIT_5_3
(或在版本名未定義時,檢查 LUA_INIT
)。
如果該變量內(nèi)存格式為 @filename
,
lua
執(zhí)行該文件。
否則,lua
執(zhí)行該字符串。
如果調(diào)用時有選項 -E
,
除了忽略 LUA_INIT
外,
Lua 還忽略 LUA_PATH
與 LUA_CPATH
的值。
將 package.path
和 package.cpath
的值設(shè)為定義在 luaconf.h
中的默認(rèn)路徑。
除 -i
與 -E
外所有的選項都按次序處理。
例如,這樣調(diào)用
$ lua -e'a=1' -e 'print(a)' script.lua
將先把 a
設(shè)為 1,然后打印 a
的值,
最后運行文件 script.lua
并不帶參數(shù)。
(這里的 $
是命令行提示。你的命令行提示可能不一樣。)
在運行任何代碼前,
lua
會將所有命令行傳入的參數(shù)放到一張全局表 arg
中。
腳本的名字放在索引 0 的地方,
腳本名后緊跟的第一個參數(shù)在索引 1 處,依次類推。
在腳本名前面的任何參數(shù)
(即解釋器的名字以及各選項)
放在負(fù)索引處。
例如,調(diào)用
$ lua -la b.lua t1 t2
這張表是這樣的:
arg = { [-2] = "lua", [-1] = "-la", [0] = "b.lua", [1] = "t1", [2] = "t2" }
如果調(diào)用中沒提供腳本名, 解釋器的名字就放在索引 0 處,后面接著其它參數(shù)。 例如,調(diào)用
$ lua -e "print(arg[1])"
將打印出 "-e
" 。
如果提供了腳本名,
就以 arg[1]
, ···, arg[#arg]
為參數(shù)調(diào)用腳本。
(和 Lua 所有的代碼塊一樣,
腳本被編譯成一個可變參數(shù)函數(shù)。)
在交互模式下, Lua 不斷的顯示提示符,并等待下一行輸入。 一旦讀到一行, 首先試著把這行解釋為一個表達(dá)式。 如果成功解釋,就打印表達(dá)式的值。 否則,將這行解釋為語句。 如果你寫了一行未完成的語句, 解釋器會用一個不同的提示符來等待你寫完。
當(dāng)腳本中出現(xiàn)了未保護(hù)的錯誤,
解釋器向標(biāo)準(zhǔn)錯誤流報告錯誤。
如果錯誤對象并非一個字符串,但是卻有元方法
__tostring
的話,
解釋器會調(diào)用這個元方法生成最終的消息。
否則,解釋器將錯誤對象轉(zhuǎn)換為一個字符串,并把?;厮菪畔⒓釉谇懊?。
如果正常結(jié)束運行,
解釋器會關(guān)閉主 Lua 狀態(tài)機
(參見 lua_close
)。
腳本可以通過調(diào)用
os.exit
來結(jié)束,以回避這個步驟。
為了讓 Lua 可以用于 Unix 系統(tǒng)的腳本解釋器。
獨立版解釋器會忽略代碼塊的以 #
打頭的第一行。
因此,Lua 腳本可以通過
chmod +x
以及 #!
形式變成一個可執(zhí)行文件。
類似這樣
#!/usr/local/bin/lua
(當(dāng)然,
Lua 解釋器的位置對于你的機器來說可能不一樣。
如果 lua
在你的 PATH
中,
寫成
#!/usr/bin/env lua
更為通用。)
這里我們列出了把程序從 Lua 5.2 遷移到 Lua 5.3 會碰到的不兼容的地方。
你可以在編譯 Lua 時定義一些恰當(dāng)?shù)倪x項(參見文件 luaconf.h
),
來回避一些不兼容性。
然而,這些兼容選項以后會移除。
Lua 的版本更替總是會修改一些 C API 并涉及源代碼的改變。 例如一些常量的數(shù)字值,用宏來實現(xiàn)一些函數(shù)。 因此,你不能假設(shè)在不同的 Lua 版本間可以做到二進(jìn)制兼容。 當(dāng)你使用新版時,一定要將使用了 Lua API 的客戶程序重新編譯。
同樣,Lua 版本更替還會改變預(yù)編譯代碼塊的內(nèi)部呈現(xiàn)方式; 在不同的 Lua 版本間,預(yù)編譯代碼塊不兼容。
官方發(fā)布版的標(biāo)準(zhǔn)路徑也可能隨版本變化。
你可以通過把數(shù)字都強制轉(zhuǎn)換為浮點數(shù)來消除差異
(在 Lua 5.2 中,所有的數(shù)字都是浮點數(shù))。
比如你可以將所有的常量都以 .0
結(jié)尾,
或是使用 x = x + 0.0
來轉(zhuǎn)換一個變量。
(這條建議僅用于偶爾快速解決一些不兼容問題;
這不是一條好的編程準(zhǔn)則。
好好寫程序的話,你應(yīng)該在需要使用浮點數(shù)的地方用浮點數(shù),
需要整數(shù)的地方用整數(shù)。)
.0
后綴。
(例如,浮點數(shù) 2.0 會被打印成 2.0
,
而不是 2
。)
如果你需要定制數(shù)字的格式,就必須顯式的格式化它們。
(準(zhǔn)確說這個不是兼容性問題, 因為 Lua 并沒有規(guī)定數(shù)字如何格式化成字符串, 但一些程序假定遵循某種特別的格式。)
bit32
庫廢棄了。
使用一個外部兼容庫很容易,
不過最好直接用對應(yīng)的位操作符來替換它。
(注意 bit32
只能針對 32 位整數(shù)運算,
而標(biāo)準(zhǔn) Lua 中的位操作可以用于 64 位整數(shù)。)
ipairs
這個迭代器也會考慮元方法,而 __ipairs
元方法被廢棄了。
io.read
的選項名不再用 '*
' 打頭。
但出于兼容性考慮,Lua 會繼續(xù)忽略掉這個字符。
atan2
, cosh
, sinh
, tanh
, pow
,
frexp
, 以及 ldexp
。
你可以用 x^y
替換 math.pow(x,y)
;
你可以用 math.atan
替換 math.atan2
,前者現(xiàn)在可以接收一或兩個參數(shù);
你可以用 x * 2.0^exp
替換 math.ldexp(x,exp)
。
若用到其它操作,你可以寫一個擴(kuò)展庫,或在 Lua 中實現(xiàn)它們。
require
在搜索 C 加載器時處理版本號的方式有所變化。
現(xiàn)在,版本號應(yīng)該跟在模塊名后(其它大多數(shù)工具都是這樣干的)。
出于兼容性考慮,如果使用新格式找不到加載器的話,搜索器依然會嘗試舊格式。
(Lua 5.2 已經(jīng)是這樣處理了,但是并沒有寫在文檔里。)
lua_getctx
獲取的參數(shù),
所以 lua_getctx
就去掉了。
按需要改寫你的代碼。
lua_dump
有了一個額外的參數(shù) strip
。
如果想和之前的行為一致,這個值傳 0 。
lua_pushunsigned
, lua_tounsigned
, lua_tounsignedx
,
luaL_checkunsigned
, luaL_optunsigned
)
都廢棄了。
直接從有符號版做類型轉(zhuǎn)換。
luaL_checkint
, luaL_optint
, luaL_checklong
, luaL_optlong
)
廢棄掉了。
直接使用 lua_Integer
加一個類型轉(zhuǎn)換就可以替代
(或是只要有可能,就在你的代碼中使用 lua_Integer
)。
這是一份采用擴(kuò)展 BNF 描述的 Lua 完整語法。 在擴(kuò)展 BNF 中, {A} 表示 0 或多個 A , [A] 表示一個可選的 A 。 (操作符優(yōu)先級,參見 §3.4.8; 對于最終符號,名字,數(shù)字,字符串字面量的解釋,參見 §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 namelist [‘=’ explist] 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 | ‘#’ | ‘~’