Lua 5.3 參考手冊

轉自:http://www.runoob.com/manual/lua53doc/manual.htmlhtml

1 – 簡介

Lua 是一門擴展式程序設計語言,被設計成支持通用過程式編程,並有相關數據描述設施。 同時對面向對象編程、函數式編程和數據驅動式編程也提供了良好的支持。 它做爲一個強大、輕量的嵌入式腳本語言,可供任何須要的程序使用。 Lua 由 clean C(標準 C 和 C++ 間共通的子集) 實現成一個庫。程序員

做爲一門擴展式語言,Lua 沒有 "main" 程序的概念: 它只能 嵌入 一個宿主程序中工做, 該宿主程序被稱爲 被嵌入程序 或者簡稱 宿主 。 宿主程序能夠調用函數執行一小段 Lua 代碼,能夠讀寫 Lua 變量,能夠註冊 C 函數讓 Lua 代碼調用。 依靠 C 函數,Lua 能夠共享相同的語法框架來定製編程語言,從而適用不一樣的領域。 Lua 的官方發佈版包含一個叫作 lua 的宿主程序示例, 它是一個利用 Lua 庫實現的完整獨立的 Lua 解釋器,可用於交互式應用或批處理。算法

Lua 是一個自由軟件,其使用許可證決定了它的使用過程無需任何擔保。 本手冊所描述的實現能夠在 Lua 的官方網站 www.lua.org 找到。數據庫

與其它的許多參考手冊同樣,這份文檔有些地方比較枯燥。 關於 Lua 背後的設計思想, 能夠看看 Lua 網站上提供的技術論文。 至於用 Lua 編程的細節介紹, 請參閱 Roberto 的書,Programming in Lua編程

2 – 基本概念

本章描述了語言的基本概念。api

2.1 – 值與類型

Lua 是一門動態類型語言。 這意味着變量沒有類型;只有值纔有類型。 語言中不設類型定義。 全部的值攜帶本身的類型。數組

Lua 中全部的值都是 一等公民。 這意味着全部的值都可保存在變量中、 看成參數傳遞給其它函數、以及做爲返回值。緩存

Lua 中有八種基本類型: nilbooleannumberstringfunctionuserdata、 thread 和 table。 Nil 是值 nil 的類型, 其主要特徵就是和其它值區別開;一般用來表示一個有意義的值不存在時的狀態。 Boolean 是 false 與 true 兩個值的類型。 nil 和 false 都會致使條件判斷爲假; 而其它任何值都表示爲真。 Number 表明了整數和實數(浮點數)。 String 表示一個不可變的字節序列。 Lua 對 8 位是友好的: 字符串能夠容納任意 8 位值, 其中包含零 ('\0') 。 Lua 的字符串與編碼無關; 它不關心字符串中具體內容。安全

number 類型有兩種內部表現方式, 整數 和 浮點數。 對於什麼時候使用哪一種內部形式,Lua 有明確的規則, 但它也按需(參見 §3.4.3)做自動轉換。 所以,程序員多數狀況下能夠選擇忽略整數與浮點數之間的差別或者假設徹底控制每一個數字的內部表現方式。 標準 Lua 使用 64 位整數和雙精度(64 位)浮點數, 但你也能夠把 Lua 編譯成使用 32 位整數和單精度(32 位)浮點數。 以 32 位表示數字對小型機器以及嵌入式系統特別合適。 (參見 luaconf.h 文件中的宏 LUA_32BITS 。)服務器

Lua 能夠調用(以及操做)用 Lua 或 C (參見 §3.4.10)編寫的函數。 這兩種函數有統一類型 function

userdata 類型容許將 C 中的數據保存在 Lua 變量中。 用戶數據類型的值是一個內存塊, 有兩種用戶數據: 徹底用戶數據 ,指一塊由 Lua 管理的內存對應的對象; 輕量用戶數據,則指一個簡單的 C 指針。 用戶數據在 Lua 中除了賦值與相等性判斷以外沒有其餘預約義的操做。 經過使用 元表 ,程序員能夠給徹底用戶數據定義一系列的操做 (參見§2.4)。 你只能經過 C API 而沒法在 Lua 代碼中建立或者修改用戶數據的值, 這保證了數據僅被宿主程序所控制。

thread 類型表示了一個獨立的執行序列,被用於實現協程 (參見 §2.6)。 Lua 的線程與操做系統的線程毫無關係。 Lua 爲全部的系統,包括那些不支持原生線程的系統,提供了協程支持。

table 是一個關聯數組, 也就是說,這個數組不只僅以數字作索引,除了 nil 和 NaN 以外的全部 Lua 值 均可以作索引。 (Not a Number 是一個特殊的數字,它用於表示未定義或表示不了的運算結果,好比 0/0。) 表能夠是 異構 的; 也就是說,表內能夠包含任何類型的值( nil 除外)。 任何鍵的值若爲 nil 就不會被記入表結構內部。 換言之,對於表內不存在的鍵,都對應着值 nil 。

表是 Lua 中惟一的數據結構, 它可被用於表示普通數組、序列、符號表、集合、記錄、圖、樹等等。 對於記錄,Lua 使用域名做爲索引。 語言提供了 a.name 這樣的語法糖來替代 a["name"] 這種寫法以方便記錄這種結構的使用。 在 Lua 中有多種便利的方式建立表(參見 §3.4.9)。

咱們使用 序列 這個術語來表示一個用 {1..n} 的正整數集作索引的表。 這裏的非負整數 n 被稱爲該序列的長度(參見 §3.4.7)。

和索引同樣,表中每一個域的值也能夠是任何類型。 須要特別指出的是:既然函數是一等公民,那麼表的域也能夠是函數。 這樣,表就能夠攜帶 方法 了。 (參見 §3.4.11)。

索引一張表的原則遵循語言中的直接比較規則。 當且僅當 i 與 j直接比較相等時 (即不經過元方法的比較), 表達式 a[i] 與 a[j] 表示了表中相同的元素。 特別指出:一個能夠徹底表示爲整數的浮點數和對應的整數相等 (例如:1.0 == 1)。 爲了消除歧義,當一個能夠徹底表示爲整數的浮點數作爲鍵值時, 都會被轉換爲對應的整數儲存。 例如,當你寫a[2.0] = true 時, 實際被插入表中的鍵是整數 2 。 (另外一方面,2 與 "2" 是兩個不一樣的 Lua 值, 故而它們能夠是同一張表中的不一樣項。)

表、函數、線程、以及徹底用戶數據在 Lua 中被稱爲 對象: 變量並不真的 持有 它們的值,而僅保存了對這些對象的 引用。 賦值、參數傳遞、函數返回,都是針對引用而不是針對值的操做, 這些操做均不會作任何形式的隱式拷貝。

庫函數 type 用於以字符串形式返回給定值的類型。 (參見 §6.1)。

2.2 – 環境與全局環境

後面在 §3.2 以及 §3.3.3 會討論, 引用一個叫 var 的自由名字(指在任何層級都未被聲明的名字) 在句法上都被翻譯爲 _ENV.var 。 此外,每一個被編譯的 Lua 代碼塊都會有一個外部的局部變量叫 _ENV (參見 §3.3.2), 所以,_ENV 這個名字永遠都不會成爲一個代碼塊中的自由名字。

在轉譯那些自由名字時,_ENV 是不是那個外部的局部變量無所謂。 _ENV 和其它你能夠使用的變量名沒有區別。 這裏特別指出,你能夠定義一個新變量或指定一個參數叫這個名字。 當編譯器在轉譯自由名字時所用到的 _ENV , 指的是你的程序在那個點上可見的那個名爲 _ENV 的變量。 (Lua 的可見性規則參見 §3.5

被 _ENV 用於值的那張表被稱爲 環境

Lua 保有一個被稱爲 全局環境 特別環境。它被保存在 C 註冊表 (參見 §4.5)的一個特別索引下。 在 Lua 中,全局變量 _G 被初始化爲這個值。 (_G 不被內部任何地方使用。)

當 Lua 加載一個代碼塊,_ENV 這個上值的默認值就是這個全局環境 (參見 load)。 所以,在默認狀況下,Lua 代碼中說起的自由名字都指的全局環境中的相關項 (所以,它們也被稱爲 全局變量 )。 此外,全部的標準庫都被加載入全局環境,一些函數也針對這個環境作操做。 你能夠用 load (或 loadfile)加載代碼塊,並賦予它們不一樣的環境。 (在 C 裏,當你加載一個代碼塊後,能夠經過改變它的第一個上值來改變它的環境。)

2.3 – 錯誤處理

因爲 Lua 是一門嵌入式擴展語言,其全部行爲均源於宿主程序中 C 代碼對某個 Lua 庫函數的調用。 (單獨使用 Lua 時,lua 程序就是宿主程序。) 因此,在編譯或運行 Lua 代碼塊的過程當中,不管什麼時候發生錯誤, 控制權都返回給宿主,由宿主負責採起恰當的措施(好比打印錯誤消息)。

能夠在 Lua 代碼中調用 error 函數來顯式地拋出一個錯誤。 若是你須要在 Lua 中捕獲這些錯誤, 能夠使用 pcall 或 xpcall 在 保護模式 下調用一個函數。

不管什麼時候出現錯誤,都會拋出一個攜帶錯誤信息的 錯誤對象 (錯誤消息)。 Lua 自己只會爲錯誤生成字符串類型的錯誤對象, 但你的程序能夠爲錯誤生成任何類型的錯誤對象, 這就看你的 Lua 程序或宿主程序如何處理這些錯誤對象。

使用 xpcall 或 lua_pcall 時, 你應該提供一個 消息處理函數 用於錯誤拋出時調用。 該函數需接收原始的錯誤消息,並返回一個新的錯誤消息。 它在錯誤發生後棧還沒有展開時調用, 所以能夠利用棧來收集更多的信息, 好比經過探知棧來建立一組棧回溯信息。 同時,該處理函數也處於保護模式下,因此該函數內發生的錯誤會再次觸發它(遞歸)。 若是遞歸太深,Lua 會終止調用並返回一個合適的消息。

2.4 – 元表及元方法

Lua 中的每一個值均可以有一個 元表。 這個 元表 就是一個普通的 Lua 表, 它用於定義原始值在特定操做下的行爲。 若是你想改變一個值在特定操做下的行爲,你能夠在它的元表中設置對應域。 例如,當你對非數字值作加操做時, Lua 會檢查該值的元表中的 "__add" 域下的函數。 若是能找到,Lua 則調用這個函數來完成加這個操做。

元表中的鍵對應着不一樣的 事件 名; 鍵關聯的那些值被稱爲 元方法。 在上面那個例子中引用的事件爲 "add" , 完成加操做的那個函數就是元方法。

你能夠用 getmetatable 函數 來獲取任何值的元表。

使用 setmetatable 來替換一張表的元表。在 Lua 中,你不能夠改變表之外其它類型的值的元表 (除非你使用調試庫(參見§6.10)); 若想改變這些非表類型的值的元表,請使用 C API。

表和徹底用戶數據有獨立的元表 (固然,多個表和用戶數據能夠共享同一個元表)。 其它類型的值按類型共享元表; 也就是說全部的數字都共享同一個元表, 全部的字符串共享另外一個元表等等。 默認狀況下,值是沒有元表的, 但字符串庫在初始化的時候爲字符串類型設置了元表 (參見 §6.4)。

元表決定了一個對象在數學運算、位運算、比較、鏈接、 取長度、調用、索引時的行爲。 元表還能夠定義一個函數,當表對象或用戶數據對象在垃圾回收 (參見§2.5)時調用它。

接下來會給出一張元表能夠控制的事件的完整列表。 每一個操做都用對應的事件名來區分。 每一個事件的鍵名用加有 '__' 前綴的字符串來表示; 例如 "add" 操做的鍵名爲字符串 "__add"。 注意、Lua 從元表中直接獲取元方法; 訪問元表中的元方法永遠不會觸發另外一次元方法。 下面的代碼模擬了 Lua 從一個對象 obj 中獲取一個元方法的過程:

     rawget(getmetatable(obj) or {}, "__" .. event_name)

對於一元操做符(取負、求長度、位反), 元方法調用的時候,第二個參數是個啞元,其值等於第一個參數。 這樣處理僅僅是爲了簡化 Lua 的內部實現 (這樣處理可讓全部的操做都和二元操做一致), 這個行爲有可能在未來的版本中移除。 (使用這個額外參數的行爲都是不肯定的。)

  • "add": + 操做。 若是任何不是數字的值(包括不能轉換爲數字的字符串)作加法, Lua 就會嘗試調用元方法。 首先、Lua 檢查第一個操做數(即便它是合法的), 若是這個操做數沒有爲 "__add" 事件定義元方法, Lua 就會接着檢查第二個操做數。 一旦 Lua 找到了元方法, 它將把兩個操做數做爲參數傳入元方法, 元方法的結果(調整爲單個值)做爲這個操做的結果。 若是找不到元方法,將拋出一個錯誤。
  • "sub": - 操做。 行爲和 "add" 操做相似。
  • "mul": * 操做。 行爲和 "add" 操做相似。
  • "div": / 操做。 行爲和 "add" 操做相似。
  • "mod": % 操做。 行爲和 "add" 操做相似。
  • "pow": ^ (次方)操做。 行爲和 "add" 操做相似。
  • "unm": - (取負)操做。 行爲和 "add" 操做相似。
  • "idiv": // (向下取整除法)操做。 行爲和 "add" 操做相似。
  • "band": & (按位與)操做。 行爲和 "add" 操做相似, 不一樣的是 Lua 會在任何一個操做數沒法轉換爲整數時 (參見 §3.4.3)嘗試取元方法。
  • "bor": | (按位或)操做。 行爲和 "band" 操做相似。
  • "bxor": ~ (按位異或)操做。 行爲和 "band" 操做相似。
  • "bnot": ~ (按位非)操做。 行爲和 "band" 操做相似。
  • "shl": << (左移)操做。 行爲和 "band" 操做相似。
  • "shr": >> (右移)操做。 行爲和 "band" 操做相似。
  • "concat": .. (鏈接)操做。 行爲和 "add" 操做相似, 不一樣的是 Lua 在任何操做數即不是一個字符串 也不是數字(數字總能轉換爲對應的字符串)的狀況下嘗試元方法。
  • "len": # (取長度)操做。 若是對象不是字符串,Lua 會嘗試它的元方法。 若是有元方法,則調用它並將對象以參數形式傳入, 而返回值(被調整爲單個)則做爲結果。 若是對象是一張表且沒有元方法, Lua 使用表的取長度操做(參見 §3.4.7)。 其它狀況,均拋出錯誤。
  • "eq": == (等於)操做。 和 "add" 操做行爲相似, 不一樣的是 Lua 僅在兩個值都是表或都是徹底用戶數據 且它們不是同一個對象時才嘗試元方法。 調用的結果總會被轉換爲布爾量。
  • "lt": < (小於)操做。 和 "add" 操做行爲相似, 不一樣的是 Lua 僅在兩個值不全爲整數也不全爲字符串時才嘗試元方法。 調用的結果總會被轉換爲布爾量。
  • "le": <= (小於等於)操做。 和其它操做不一樣, 小於等於操做可能用到兩個不一樣的事件。 首先,像 "lt" 操做的行爲那樣,Lua 在兩個操做數中查找 "__le" 元方法。 若是一個元方法都找不到,就會再次查找 "__lt" 事件, 它會假設 a <= b 等價於 not (b < a)。 而其它比較操做符相似,其結果會被轉換爲布爾量。
  • "index": 索引 table[key]。 當 table 不是表或是表 table 中不存在 key 這個鍵時,這個事件被觸發。 此時,會讀出 table 相應的元方法。

    儘管名字取成這樣, 這個事件的元方法其實能夠是一個函數也能夠是一張表。 若是它是一個函數,則以 table 和 key 做爲參數調用它。 若是它是一張表,最終的結果就是以key 取索引這張表的結果。 (這個索引過程是走常規的流程,而不是直接索引, 因此此次索引有可能引起另外一次元方法。)

  • "newindex": 索引賦值 table[key] = value 。 和索引事件相似,它發生在 table 不是表或是表 table 中不存在 key 這個鍵的時候。 此時,會讀出 table 相應的元方法。

    同索引過程那樣, 這個事件的元方法便可以是函數,也能夠是一張表。 若是是一個函數, 則以 table、 key、以及 value 爲參數傳入。 若是是一張表, Lua 對這張表作索引賦值操做。 (這個索引過程是走常規的流程,而不是直接索引賦值, 因此此次索引賦值有可能引起另外一次元方法。)

    一旦有了 "newindex" 元方法, Lua 就再也不作最初的賦值操做。 (若是有必要,在元方法內部能夠調用 rawset 來作賦值。)

  • "call": 函數調用操做 func(args)。 當 Lua 嘗試調用一個非函數的值的時候會觸發這個事件 (即 func 不是一個函數)。 查找 func 的元方法, 若是找獲得,就調用這個元方法, func 做爲第一個參數傳入,原來調用的參數(args)後依次排在後面。

2.5 – 垃圾收集

Lua 採用了自動內存管理。 這意味着你不用操心新建立的對象須要的內存如何分配出來, 也不用考慮在對象再也不被使用後怎樣釋放它們所佔用的內存。 Lua 運行了一個 垃圾收集器 來收集全部 死對象 (即在 Lua 中不可能再訪問到的對象)來完成自動內存管理的工做。 Lua 中全部用到的內存,如:字符串、表、用戶數據、函數、線程、 內部結構等,都服從自動管理。

Lua 實現了一個增量標記-掃描收集器。 它使用這兩個數字來控制垃圾收集循環: 垃圾收集器間歇率 和 垃圾收集器步進倍率。 這兩個數字都使用百分數爲單位 (例如:值 100 在內部表示 1 )。

垃圾收集器間歇率控制着收集器須要在開啓新的循環前要等待多久。 增大這個值會減小收集器的積極性。 當這個值比 100 小的時候,收集器在開啓新的循環前不會有等待。 設置這個值爲 200 就會讓收集器等到總內存使用量達到 以前的兩倍時纔開始新的循環。

垃圾收集器步進倍率控制着收集器運做速度相對於內存分配速度的倍率。 增大這個值不只會讓收集器更加積極,還會增長每一個增量步驟的長度。 不要把這個值設得小於 100 , 那樣的話收集器就工做的太慢了以致於永遠都幹不完一個循環。 默認值是 200 ,這表示收集器之內存分配的「兩倍」速工做。

若是你把步進倍率設爲一個很是大的數字 (比你的程序可能用到的字節數還大 10% ), 收集器的行爲就像一個 stop-the-world 收集器。 接着你若把間歇率設爲 200 , 收集器的行爲就和過去的 Lua 版本同樣了: 每次 Lua 使用的內存翻倍時,就作一次完整的收集。

你能夠經過在 C 中調用 lua_gc 或在 Lua 中調用 collectgarbage 來改變這倆數字。 這兩個函數也能夠用來直接控制收集器(例如中止它或重啓它)。

2.5.1 – 垃圾收集元方法

你能夠爲表設定垃圾收集的元方法, 對於徹底用戶數據(參見 §2.4), 則須要使用 C API 。 該元方法被稱爲 終結器。 終結器容許你配合 Lua 的垃圾收集器作一些額外的資源管理工做 (例如關閉文件、網絡或數據庫鏈接,或是釋放一些你本身的內存)。

若是要讓一個對象(表或用戶數據)在收集過程當中進入終結流程, 你必須 標記 它須要觸發終結器。 當你爲一個對象設置元表時,若此刻這張元表中用一個以字符串 "__gc" 爲索引的域,那麼就標記了這個對象須要觸發終結器。 注意:若是你給對象設置了一個沒有 __gc 域的元表,以後纔給元表加上這個域, 那麼這個對象是沒有被標記成須要觸發終結器的。 然而,一旦對象被標記, 你仍是能夠自由的改變其元表中的 __gc 域的。

當一個被標記的對象成爲了垃圾後, 垃圾收集器並不會馬上回收它。 取而代之的是,Lua 會將其置入一個鏈表。 在收集完成後,Lua 將遍歷這個鏈表。 Lua 會檢查每一個鏈表中的對象的 __gc 元方法:若是是一個函數,那麼就以對象爲惟一參數調用它; 不然直接忽略它。

在每次垃圾收集循環的最後階段, 本次循環中檢測到的須要被回收之對象, 其終結器的觸發次序按當初給對象做須要觸發終結器的標記之次序的逆序進行; 這就是說,第一個被調用的終結器是程序中最後一個被標記的對象所攜的那個。 每一個終結器的運行可能發生在執行常規代碼過程當中的任意一刻。

因爲被回收的對象還須要被終結器使用, 該對象(以及僅能經過它訪問到的其它對象)必定會被 Lua 復活。 一般,復活是短暫的,對象所屬內存會在下一個垃圾收集循環釋放。 而後,若終結器又將對象保存去一些全局的地方 (例如:放在一個全局變量裏),此次復活就持續生效了。 此外,若是在終結器中對一個正進入終結流程的對象再次作一次標記讓它觸發終結器, 只要這個對象在下個循環中依舊不可達,它的終結函數還會再調用一次。 不管是哪一種狀況, 對象所屬內存僅在垃圾收集循環中該對象不可達且 沒有被標記成須要觸發終結器纔會被釋放。

當你關閉一個狀態機(參見 lua_close), Lua 將調用全部被標記了須要觸發終結器對象的終結過程, 其次序爲標記次序的逆序。 在這個過程當中,任何終結器再次標記對象的行爲都不會生效。

2.5.2 – 弱表

弱表 指內部元素爲 弱引用 的表。 垃圾收集器會忽略掉弱引用。 換句話說,若是一個對象只被弱引用引用到, 垃圾收集器就會回收這個對象。

一張弱表能夠有弱鍵或是弱值,也能夠鍵值都是弱引用。 僅含有弱鍵的表容許收集器回收它的鍵,但會阻止對值所指的對象被回收。 若一張表的鍵值均爲弱引用, 那麼收集器能夠回收其中的任意鍵和值。 任何狀況下,只要鍵或值的任意一項被回收, 相關聯的鍵值對都會從表中移除。 一張表的元表中的 __mode 域控制着這張表的弱屬性。 當 __mode 域是一個包含字符 'k' 的字符串時,這張表的全部鍵皆爲弱引用。 當 __mode 域是一個包含字符 'v' 的字符串時,這張表的全部值皆爲弱引用。

屬性爲弱鍵強值的表也被稱爲 暫時表。 對於一張暫時表, 它的值是否可達僅取決於其對應鍵是否可達。 特別注意,若是表內的一個鍵僅僅被其值所關聯引用, 這個鍵值對將被表內移除。

對一張表的弱屬性的修改僅在下次收集循環才生效。 尤爲是當你把表由弱改強,Lua 仍是有可能在修改生效前回收表內一些項目。

只有那些有顯式構造過程的對象纔會從弱表中移除。 值,例如數字和輕量 C 函數,不受垃圾收集器管轄, 所以不會從弱表中移除 (除非它們的關聯項被回收)。 雖然字符串受垃圾回收器管轄, 但它們沒有顯式的構造過程,因此也不會從弱表中移除。

弱錶針對復活的對象 (指那些正在走終結流程,僅能被終結器訪問的對象) 有着特殊的行爲。 弱值引用的對象,在運行它們的終結器前就被移除了, 而弱鍵引用的對象則要等到終結器運行完畢後,到下次收集當對象真的被釋放時才被移除。 這個行爲使得終結器運行時得以訪問到由該對象在弱表中所關聯的屬性。

若是一張弱表在當次收集循環內的復活對象中, 那麼在下個循環前這張表有可能未被正確地清理。

2.6 – 協程

Lua 支持協程,也叫 協同式多線程。 一個協程在 Lua 中表明瞭一段獨立的執行線程。 然而,與多線程系統中的線程的區別在於, 協程僅在顯式調用一個讓出(yield)函數時才掛起當前的執行。

調用函數 coroutine.create 可建立一個協程。 其惟一的參數是該協程的主函數。 create 函數只負責新建一個協程並返回其句柄 (一個 thread 類型的對象); 而不會啓動該協程。

調用 coroutine.resume 函數執行一個協程。 第一次調用 coroutine.resume 時,第一個參數應傳入 coroutine.create 返回的線程對象,而後協程從其主函數的第一行開始執行。 傳遞給 coroutine.resume 的其餘參數將做爲協程主函數的參數傳入。 協程啓動以後,將一直運行到它終止或 讓出

協程的運行可能被兩種方式終止: 正常途徑是主函數返回 (顯式返回或運行完最後一條指令); 非正常途徑是發生了一個未被捕獲的錯誤。 對於正常結束, coroutine.resume將返回 true, 並接上協程主函數的返回值。 當錯誤發生時, coroutine.resume 將返回 false 與錯誤消息。

經過調用 coroutine.yield 使協程暫停執行,讓出執行權。 協程讓出時,對應的最近 coroutine.resume 函數會馬上返回,即便該讓出操做發生在內嵌函數調用中 (即不在主函數,但在主函數直接或間接調用的函數內部)。 在協程讓出的狀況下, coroutine.resume 也會返回 true, 並加上傳給 coroutine.yield 的參數。 當下次重啓同一個協程時, 協程會接着從讓出點繼續執行。 調用coroutine.yield 會返回任何傳給 coroutine.resume 的第一個參數以外的其餘參數。

與 coroutine.create 相似, coroutine.wrap 函數也會建立一個協程。 不一樣之處在於,它不返回協程自己,而是返回一個函數。 調用這個函數將啓動該協程。 傳遞給該函數的任何參數均看成 coroutine.resume 的額外參數。 coroutine.wrap 返回 coroutine.resume 的全部返回值,除了第一個返回值(布爾型的錯誤碼)。 和 coroutine.resume不一樣, coroutine.wrap 不會捕獲錯誤; 而是將任何錯誤都傳播給調用者。

下面的代碼展現了一個協程工做的範例:

     function foo (a)
       print("foo", a)
       return coroutine.yield(2*a)
     end
     
     co = coroutine.create(function (a,b)
           print("co-body", a, b)
           local r = foo(a+1)
           print("co-body", r)
           local r, s = coroutine.yield(a+b, a-b)
           print("co-body", r, s)
           return b, "end"
     end)
     
     print("main", coroutine.resume(co, 1, 10))
     print("main", coroutine.resume(co, "r"))
     print("main", coroutine.resume(co, "x", "y"))
     print("main", coroutine.resume(co, "x", "y"))

當你運行它,將產生下列輸出:

     co-body 1       10
     foo     2
     main    true    4
     co-body r
     main    true    11      -9
     co-body x       y
     main    true    10      end
     main    false   cannot resume dead coroutine

你也能夠經過 C API 來建立及操做協程: 參見函數 lua_newthread, lua_resume, 以及 lua_yield

3 – 語言定義

這一章描述了 Lua 的詞法、語法和句法。 換句話說,本章描述哪些符記是有效的, 它們如何被組合起來,這些組合方式有什麼含義。

關於語言的構成概念將用常見的擴展 BNF 表達式寫出。 也就是這個樣子: {a} 表示 0 或多個 a, [a] 表示一個可選的 a。 能夠被分解的非最終符號會這樣寫 non-terminal , 關鍵字會寫成這樣 kword, 而其它不能被分解的最終符號則寫成這樣 ‘=’ 。 完整的 Lua 語法能夠在本手冊最後一章 §9 找到。

3.1 – 詞法約定

Lua 語言的格式自由。 它會忽略語法元素(符記)間的空格(包括換行)和註釋, 僅把它們看做爲名字和關鍵字間的分割符。

Lua 中的 名字 (也被稱爲 標識符) 能夠是由非數字打頭的任意字母下劃線和數字構成的字符串。 標識符可用於對變量、表的域、以及標籤命名。

下列 關鍵字 是保留的,不可用於名字:

     and       break     do        else      elseif    end
     false     for       function  goto      if        in
     local     nil       not       or        repeat    return
     then      true      until     while

Lua 語言對大小寫敏感: and 是一個保留字,但 And 與 AND 則是兩個不一樣的有效名字。 做爲一個約定,程序應避免建立如下劃線加一個或多個大寫字母構成的名字 (例如_VERSION)。

下列字符串是另一些符記:

     +     -     *     /     %     ^     #
     &     ~     |     <<    >>    //
     ==    ~=    <=    >=    <     >     =
     (     )     {     }     [     ]     ::
     ;     :     ,     .     ..    ...

字面串 能夠用單引號或雙引號括起。 字面串內部能夠包含下列 C 風格的轉義串: '\a' (響鈴), '\b' (退格), '\f' (換頁), '\n' (換行), '\r' (回車), '\t' (橫項製表), '\v' (縱向製表), '\\' (反斜槓), '\"' (雙引號), 以及 '\'' (單引號)。 在反斜槓後跟一個真正的換行等價於在字符串中寫一個換行符。 轉義串 '\z' 會忽略其後的一系列空白符,包括換行; 它在你須要對一個很長的字符串常量斷行爲多行並但願在每一個新行保持縮進時很是有用。

Lua 中的字符串能夠保存任意 8 位值,其中包括用 '\0' 表示的 0 。 通常而言,你能夠用字符的數字值來表示這個字符。 方式是用轉義串 \xXX, 此處的 XX 必須是剛好兩個字符的 16 進制數。 或者你也能夠使用轉義串 \ddd , 這裏的 ddd 是一到三個十進制數字。 (注意,若是在轉義符後接着恰巧是一個數字符號的話, 你就必須在這個轉義形式中寫滿三個數字。)

對於用 UTF-8 編碼的 Unicode 字符,你能夠用 轉義符 \u{XXX} 來表示 (這裏必須有一對花括號), 此處的 XXX 是用 16 進製表示的字符編號。

字面串還能夠用一種 長括號 括起來的方式定義。 咱們把兩個正的方括號間插入 n 個等號定義爲 第 n 級開長括號。 就是說,0 級開的長括號寫做 [[ , 一級開長括號寫做 [=[ , 如此等等。 閉長括號也做相似定義; 舉個例子,4 級反的長括號寫做 ]====] 。 一個 長字面串 能夠由任何一級的開長括號開始,而由第一個碰到的同級的閉長括號結束。 這種方式描述的字符串能夠包含任何東西,固然特定級別的反長括號除外。 整個詞法分析過程將不受分行限制,不處理任何轉義符,而且忽略掉任何不一樣級別的長括號。 其中碰到的任何形式的換行串(回車、換行、回車加換行、換行加回車),都會被轉換爲單個換行符。

字面串中的每一個不被上述規則影響的字節都呈現爲自己。 然而,Lua 是用文本模式打開源文件解析的, 一些系統的文件操做函數對某些控制字符的處理可能有問題。 所以,對於非文本數據,用引號括起來並顯式按轉義符規則來表述更安全。

爲了方便起見, 當一個開長括號後緊接一個換行符時, 這個換行符不會放在字符串內。 舉個例子,假設一個系統使用 ASCII 碼 (此時 'a' 編碼爲 97 , 換行編碼爲 10 ,'1' 編碼爲 49 ), 下面五種方式描述了徹底相同的字符串:

     a = 'alo\n123"'
     a = "alo\n123\""
     a = '\97lo\10\04923"'
     a = [[alo
     123"]]
     a = [==[
     alo
     123"]==]

數字常量 (或稱爲 數字量) 能夠由可選的小數部分和可選的十爲底的指數部分構成, 指數部分用字符 'e' 或 'E' 來標記。 Lua 也接受以 0x 或 0X 開頭的 16 進制常量。 16 進制常量也接受小數加指數部分的形式,指數部分是以二爲底, 用字符 'p' 或 'P' 來標記。 數字常量中包含小數點或指數部分時,被認爲是一個浮點數; 不然被認爲是一個整數。 下面有一些合法的整數常量的例子:

     3   345   0xff   0xBEBADA

如下爲合法的浮點常量:

     3.0     3.1416     314.16e-2     0.31416E1     34e1
     0x0.1E  0xA23p-4   0X1.921FB54442D18P+1

在字符串外的任何地方出現以雙橫線 (--) 開頭的部分是 註釋 。 若是 -- 後沒有緊跟着一個開大括號, 該註釋爲 短註釋, 註釋到當前行末截至。 不然,這是一段 長註釋 , 註釋區一直維持到對應的閉長括號。 長註釋一般用於臨時屏蔽掉一大段代碼。

3.2 – 變量

變量是儲存值的地方。 Lua 中有三種變量: 全局變量、局部變量和表的域。

單個名字能夠指代一個全局變量也能夠指代一個局部變量 (或者是一個函數的形參,這是一種特殊形式的局部變量)。

	var ::= Name

名字指 §3.1 中定義的標識符。

全部沒有顯式聲明爲局部變量(參見 §3.3.7) 的變量名都被當作全局變量。 局部變量有其 做用範圍 : 局部變量能夠被定義在它做用範圍中的函數自由使用(參見 §3.5)。

在變量的首次賦值以前,變量的值均爲 nil

方括號被用來對錶做索引:

	var ::= prefixexp ‘[’ exp ‘]

對全局變量以及表的域之訪問的含義能夠經過元表來改變。 以索引方式訪問一個變量 t[i] 等價於 調用 gettable_event(t,i)。 (參見 §2.4 ,有一份完整的關於 gettable_event函數的說明。 這個函數並無在 lua 中定義出來,也不能在 lua 中調用。這裏咱們把提到它只是方便說明問題。)

var.Name 這種語法只是一個語法糖,用來表示 var["Name"]

	var ::= prefixexp ‘.’ Name

對全局變量 x 的操做等價於操做 _ENV.x。 因爲代碼塊編譯的方式, _ENV 永遠也不多是一個全局名字 (參見 §2.2)。

3.3 – 語句

Lua 支持全部與 Pascal 或是 C 相似的常見形式的語句, 這個集合包括賦值,控制結構,函數調用,還有變量聲明。

3.3.1 – 語句塊

語句塊是一個語句序列,它們會按次序執行:

	block ::= {stat}

Lua 支持 空語句, 你能夠用分號分割語句,也能夠以分號開始一個語句塊, 或是連着寫兩個分號:

	stat ::= ‘;

函數調用和賦值語句均可能以一個小括號打頭, 這可能讓 Lua 的語法產生歧義。 咱們來看看下面的代碼片段:

     a = b + c
     (print or io.write)('done')

從語法上說,可能有兩種解釋方式:

     a = b + c(print or io.write)('done')
     
     a = b + c; (print or io.write)('done')

當前的解析器老是用第一種結構來解析, 它會將開括號當作函數調用的參數傳遞開始處。 爲了不這種二義性, 在一條語句以小括號開頭時,前面放一個分號是個好習慣:

     ;(print or io.write)('done')

一個語句塊能夠被顯式的定界爲單條語句:

	stat ::= do block end

顯式的對一個塊定界一般用來控制內部變量聲明的做用域。 有時,顯式定界也用於在一個語句塊中間插入 return (參見 §3.3.4)。

3.3.2 – 代碼塊

Lua 的一個編譯單元被稱爲一個 代碼塊。 從句法構成上講,一個代碼塊就是一個語句塊。

	chunk ::= block

Lua 把一個代碼塊看成一個擁有不定參數的匿名函數 (參見§3.4.11)來處理。 正是這樣,代碼塊內能夠定義局部變量,它能夠接收參數,返回若干值。 此外,這個匿名函數在編譯時還爲它的做用域綁定了一個外部局部變量 _ENV (參見 §2.2)。 該函數老是把 _ENV 做爲它惟一的一個上值, 即便這個函數不使用這個變量,它也存在。

代碼塊能夠被保存在文件中,也能夠做爲宿主程序內部的一個字符串。 要執行一個代碼塊, 首先要讓 Lua 加載 它, 將代碼塊中的代碼預編譯成虛擬機中的指令, 然後,Lua 用虛擬機解釋器來運行編譯後的代碼。

代碼塊能夠被預編譯爲二進制形式; 參見程序 luac 以及函數 string.dump 可得到更多細節。 用源碼錶示的程序和編譯後的形式可自由替換; Lua 會自動檢測文件格式作相應的處理 (參見 load)。

3.3.3 – 賦值

Lua 容許多重賦值。 所以,賦值的語法定義是等號左邊放一個變量列表, 而等號右邊放一個表達式列表。 兩邊的列表中的元素都用逗號間開:

	stat ::= varlist ‘=’ explist
	varlist ::= var {‘,’ var}
	explist ::= exp {‘,’ exp}

表達式放在 §3.4 中討論。

在做賦值操做以前, 那值列表會被 調整 爲左邊變量列表的個數。 若是值比須要的更多的話,多餘的值就被扔掉。 若是值的數量不夠需求, 將會按所需擴展若干個 nil。 若是表達式列表以一個函數調用結束, 這個函數所返回的全部值都會在調整操做以前被置入值列表中 (除非這個函數調用被用括號括了起來;參見 §3.4)。

賦值語句首先讓全部的表達式完成運算, 以後再作賦值操做。 所以,下面這段代碼

     i = 3
     i, a[i] = i+1, 20

會把 a[3] 設置爲 20,而不會影響到 a[4] 。 這是由於 a[i] 中的 i 在被賦值爲 4 以前就被計算出來了(當時是 3 )。 簡單說 ,這樣一行

     x, y = y, x

會交換 x 和 y 的值, 及

     x, y, z = y, z, x

會輪換 xyz 的值。

對全局變量以及表的域的賦值操做的含義能夠經過元表來改變。 對 t[i] = val 這樣的變量索引賦值, 等價於 settable_event(t,i,val)。 (關於函數 settable_event 的詳細說明,參見 §2.4。 這個函數並無在 Lua 中定義出來,也不能夠被調用。 這裏咱們列出來,僅僅出於方便解釋的目的。)

對於全局變量 x = val 的賦值等價於 _ENV.x = val (參見 §2.2)。

3.3.4 – 控制結構

ifwhile, and repeat 這些控制結構符合一般的意義,並且也有相似的語法:

	stat ::= while exp do block end
	stat ::= repeat block until exp
	stat ::= if exp then block {elseif exp then block} [else block] end

Lua 也有一個 for 語句,它有兩種形式 (參見 §3.3.5)。

控制結構中的條件表達式能夠返回任何值。 false 與 nil 二者都被認爲是假。 全部不一樣於 nil 與 false 的其它值都被認爲是真 (特別須要注意的是,數字 0 和空字符串也被認爲是真)。

在 repeatuntil 循環中, 內部語句塊的結束點不是在 until 這個關鍵字處, 它還包括了其後的條件表達式。 所以,條件表達式中能夠使用循環內部語句塊中的定義的局部變量。

goto 語句將程序的控制點轉移到一個標籤處。 因爲句法上的緣由, Lua 裏的標籤也被認爲是語句:

	stat ::= goto Name
	stat ::= label
	label ::= ‘::’ Name ‘::

除了在內嵌函數中,以及在內嵌語句塊中定義了同名標籤,的狀況外, 標籤對於它定義所在的整個語句塊可見。 只要 goto 沒有進入一個新的局部變量的做用域,它能夠跳轉到任意可見標籤處。

標籤和沒有內容的語句被稱爲空語句,它們不作任何操做。

break 被用來結束 while、 repeat、或 for 循環, 它將跳到循環外接着以後的語句運行:

	stat ::= break

break 跳出最內層的循環。

return 被用於從函數或是代碼塊(其實它就是一個函數) 中返回值。 函數能夠返回不止一個值,因此 return 的語法爲

	stat ::= return [explist] [‘;’]

return 只能被寫在一個語句塊的最後一句。 若是你真的須要從語句塊的中間 return, 你能夠使用顯式的定義一個內部語句塊, 通常寫做 do return end。 能夠這樣寫是由於如今 return 成了(內部)語句塊的最後一句了。

3.3.5 – For 語句

for 有兩種形式:一種是數字形式,另外一種是通用形式。

數字形式的 for 循環,經過一個數學運算不斷地運行內部的代碼塊。 下面是它的語法:

	stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end

block 將把 name 做循環變量。 從第一個 exp 開始起,直到第二個 exp 的值爲止, 其步長爲第三個 exp 。 更確切的說,一個 for 循環看起來是這個樣子

     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

注意下面這幾點:

  • 全部三個控制表達式都只被運算一次, 表達式的計算在循環開始以前。 這些表達式的結果必須是數字。
  • varlimit,以及 step 都是一些不可見的變量。 這裏給它們起的名字都僅僅用於解釋方便。
  • 若是第三個表達式(步長)沒有給出,會把步長設爲 1 。
  • 你能夠用 break 和 goto 來退出 for 循環。
  • 循環變量 v 是一個循環內部的局部變量; 若是你須要在循環結束後使用這個值, 在退出循環前把它賦給另外一個變量。

通用形式的 for 經過一個叫做 迭代器 的函數工做。 每次迭代,迭代器函數都會被調用以產生一個新的值, 當這個值爲 nil 時,循環中止。 通用形式的 for 循環的語法以下:

	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 只會被計算一次。 它返回三個值, 一個 迭代器 函數, 一個 狀態, 一個 迭代器的初始值
  • f, s,與 var 都是不可見的變量。 這裏給它們起的名字都只是爲了解說方便。
  • 你能夠使用 break 來跳出 for 循環。
  • 環變量 var_i 對於循環來講是一個局部變量; 你不能夠在 for 循環結束後繼續使用。 若是你須要保留這些值,那麼就在循環跳出或結束前賦值到別的變量裏去。

3.3.6 – 函數調用語句

爲了容許使用函數的反作用, 函數調用能夠被做爲一個語句執行:

	stat ::= functioncall

在這種狀況下,全部的返回值都被捨棄。 函數調用在 §3.4.10 中解釋。

3.3.7 – 局部聲明

局部變量能夠在語句塊中任何地方聲明。 聲明能夠包含一個初始化賦值操做:

	stat ::= local namelist [‘=’ explist]

若是有初始化值的話,初始化賦值操做的語法和賦值操做一致 (參見 §3.3.3 )。 若沒有初始化值,全部的變量都被初始化爲 nil

一個代碼塊同時也是一個語句塊(參見 §3.3.2), 因此局部變量能夠放在代碼塊中那些顯式註明的語句塊以外。

局部變量的可見性規則在 §3.5 中解釋。

3.4 – 表達式

Lua 中有這些基本表達式:

	exp ::= prefixexp
	exp ::= nil | false | true
	exp ::= Numeral
	exp ::= LiteralString
	exp ::= functiondef
	exp ::= tableconstructor
	exp ::= ‘...’
	exp ::= exp binop exp
	exp ::= unop exp
	prefixexp ::= var | functioncall | ‘(’ exp ‘)

數字和字面串在 §3.1 中解釋; 變量在 §3.2 中解釋; 函數定義在 §3.4.11 中解釋; 函數調用在 §3.4.10 中解釋; 表的構造在 §3.4.9 中解釋。 可變參數的表達式寫做三個點('...'), 它只能在有可變參數的函數中直接使用;這些在 §3.4.11 中解釋。

二元操做符包含有數學運算操做符(參見 §3.4.1), 位操做符(參見 §3.4.2), 比較操做符(參見 §3.4.4), 邏輯操做符(參見 §3.4.5), 以及鏈接操做符(參見 §3.4.6)。 一元操做符包括負號(參見 §3.4.1), 按位非(參見 §3.4.2), 邏輯非(參見 §3.4.5), 和取長度操做符(參見 §3.4.7)。

函數調用和可變參數表達式均可以放在多重返回值中。 若是函數調用被看成一條語句(參見 §3.3.6), 其返回值列表被調整爲零個元素,即拋棄全部的返回值。 若是表達式被用於表達式列表的最後(或是惟一的)一個元素, 那麼不會作任何調整(除非表達式被括號括起來)。 在其它狀況下, Lua 都會把結果調整爲一個元素置入表達式列表中, 即保留第一個結果而忽略以後的全部值,或是在沒有結果時, 補單個 nil

這裏有一些例子:

     f()                -- 調整爲 0 個結果
     g(f(), x)          -- f() 會被調整爲一個結果
     g(x, f())          -- g 收到 x 以及 f() 返回的全部結果
     a,b,c = f(), x     -- f() 被調整爲 1 個結果 (c 收到 nil)
     a,b = ...          -- a 收到可變參數列表的第一個參數,
                        -- b 收到第二個參數(若是可變參數列表中
                        -- 沒有實際的參數,a 和 b 都會收到 nil)
     
     a,b,c = x, f()     -- f() 被調整爲 2 個結果
     a,b,c = f()        -- f() 被調整爲 3 個結果
     return f()         -- 返回 f() 的全部返回結果
     return ...         -- 返回從可變參數列表中接收到的全部參數parameters
     return x,y,f()     -- 返回 x, y, 以及 f() 的全部返回值
     {f()}              -- 用 f() 的全部返回值建立一個列表
     {...}              -- 用可變參數中的全部值建立一個列表
     {f(), nil}         -- f() 被調整爲一個結果

被括號括起來的表達式永遠被看成一個值。 因此, (f(x,y,z)) 即便 f 返回多個值, 這個表達式永遠是一個單一值。 ((f(x,y,z)) 的值是 f 返回的第一個值。 若是 f 不返回值的話,那麼它的值就是 nil 。)

3.4.1 – 數學運算操做符

Lua 支持下列數學運算操做符:

  • +加法
  • -減法
  • *乘法
  • /浮點除法
  • //向下取整除法
  • %取模
  • ^乘方
  • -取負

除了乘方和浮點除法運算, 數學運算按以下方式工做: 若是兩個操做數都是整數, 該操做以整數方式操做且結果也將是一個整數。 不然,當兩個操做數都是數字或能夠被轉換爲數字的字符串 (參見 §3.4.3)時, 操做數會被轉換成兩個浮點數, 操做按一般的浮點規則(通常遵循 IEEE 754 標準) 來進行,結果也是一個浮點數。

乘方和浮點除法 (/) 老是把操做數轉換成浮點數進行,其結果老是浮點數。 乘方使用 ISO C 函數 pow, 所以它也能夠接受非整數的指數。

向下取整的除法 (//) 指作一次除法,並將商圓整到靠近負無窮的一側, 即對操做數作除法後取 floor 。

取模被定義成除法的餘數,其商被圓整到靠近負無窮的一側(向下取整的除法)。

對於整數數學運算的溢出問題, 這些操做採起的策略是按一般遵循的以 2 爲補碼的數學運算的 環繞 規則。 (換句話說,它們返回其運算的數學結果對 264 取模後的數字。)

3.4.2 – 位操做符

Lua 支持下列位操做符:

  • &按位與
  • |按位或
  • ~按位異或
  • >>右移
  • <<左移
  • ~按位非

全部的位操做都將操做數先轉換爲整數 (參見 §3.4.3), 而後按位操做,其結果是一個整數。

對於右移和左移,均用零來填補空位。 移動的位數若爲負,則向反方向位移; 若移動的位數的絕對值大於等於 整數自己的位數,其結果爲零 (全部位都被移出)。

3.4.3 – 強制轉換

Lua 對一些類型和值的內部表示會在運行時作一些數學轉換。 位操做老是將浮點操做數轉換成整數。 乘方和浮點除法老是將整數轉換爲浮點數。 其它數學操做若針對混合操做數 (整數和浮點數)將把整數轉換爲浮點數; 這一點被稱爲 一般規則。 C API 一樣會按需把整數轉換爲浮點數以及 把浮點數轉換爲整數。 此外,字符串鏈接操做除了字符串,也能夠接受數字做爲參數。

當操做須要數字時,Lua 還會把字符串轉換爲數字。

當把一個整數轉換爲浮點數時, 若整數值剛好能夠表示爲一個浮點數,那就取那個浮點數。 不然,轉換會取最接近的較大值或較小值來表示這個數。 這種轉換是不會失敗的。

將浮點數轉爲整數的過程會檢查 浮點數可否被準確的表達爲一個整數 (即,浮點數是一個整數值且在整數能夠表達的區間)。 若是能夠,結果就是那個數,不然轉換失敗。

從字符串到數字的轉換過程遵循如下流程: 首先,遵循按 Lua 詞法分析器的規則分析語法來轉換爲對應的 整數或浮點數。 (字符串能夠有前置或後置的空格以及一個符號。) 而後,結果數字再按前述規則轉換爲所須要的類型(浮點或整數)。

從數字轉換爲字符串使用非指定的人可讀的格式。 若想徹底控制數字到字符串的轉換過程, 能夠使用字符串庫中的 format 函數 (參見 string.format)。

3.4.4 – 比較操做符

Lua 支持下列比較操做符:

  • ==等於
  • ~=不等於
  • <小於
  • >大於
  • <=小於等於
  • >=大於等於

這些操做的結果不是 false 就是 true

等於操做 (==)先比較操做數的類型。 若是類型不一樣,結果就是 false。 不然,繼續比較值。 字符串按通常的方式比較。 數字遵循二元操做的規則: 若是兩個操做數都是整數, 它們按整數比較; 不然,它們先轉換爲浮點數,而後再作比較。

表,用戶數據,以及線程都按引用比較: 只有二者引用同一個對象時才認爲它們相等。 每次你建立一個新對象(一張表,一個用戶數據,或一個線程), 新對象都必定和已有且存在的對象不一樣。 相同引用的閉包必定相等。 有任何可察覺的差別(不一樣的行爲,不一樣的定義)必定不等。

你能夠經過使用 "eq" 元方法(參見 §2.4) 來改變 Lua 比較表和用戶數據時的方式。

等於操做不會將字符串轉換爲數字,反之亦然。 即,"0"==0 結果爲 false, 且 t[0] 與 t["0"] 指代着表中的不一樣項。

~= 操做徹底等價於 (==) 操做的反值。

大小比較操做以如下方式進行。 若是參數都是數字, 它們按二元操做的常規進行。 不然,若是兩個參數都是字符串, 它們的值按當前的區域設置來比較。 再則,Lua 就試着調用 "lt" 或是 "le" 元方法 (參見 §2.4)。 a > b 的比較被轉譯爲 b < a, a >= b 被轉譯爲 b <= a

3.4.5 – 邏輯操做符

Lua 中的邏輯操做符有 and, or,以及 not。 和控制結構(參見 §3.3.4)同樣, 全部的邏輯操做符把 false 和 nil 都做爲假, 而其它的一切都看成真。

取反操做 not 老是返回 false 或 true 中的一個。 與操做符 and 在第一個參數爲 false 或 nil 時 返回這第一個參數; 不然,and 返回第二個參數。 或操做符 or 在第一個參數不爲 nil 也不爲 false 時, 返回這第一個參數,不然返回第二個參數。 and 和 or 都遵循短路規則; 也就是說,第二個操做數只在須要的時候去求值。 這裏有一些例子:

     10 or 20            --> 10
     10 or error()       --> 10
     nil or "a"          --> "a"
     nil and 10          --> nil
     false and error()   --> false
     false and nil       --> false
     false or nil        --> nil
     10 and 20           --> 20

(在這本手冊中, --> 指前面表達式的結果。)

3.4.6 – 字符串鏈接

Lua 中字符串的鏈接操做符寫做兩個點('..')。 若是兩個操做數都是字符串或都是數字, 鏈接操做將以 §3.4.3 中提到的規則把其轉換爲字符串。 不然,會調用元方法 __concat(參見 §2.4)。

3.4.7 – 取長度操做符

取長度操做符寫做一元前置符 #。 字符串的長度是它的字節數(就是以一個字符一個字節計算的字符串長度)。

程序能夠經過 __len 元方法(參見 §2.4) 來修改對字符串類型外的任何值的取長度操做行爲。

若是 __len 元方法沒有給出, 表 t 的長度只在表是一個 序列 時有定義。 序列指表的正數鍵集等於 {1..n} , 其中 n 是一個非負整數。 在這種狀況下,n 是表的長度。 注意這樣的表

     {10, 20, nil, 40}

不是一個序列,由於它有鍵 4 卻沒有鍵 3。 (所以,該表的正整數鍵集不等於 {1..n} 集合,故而就不存在 n。) 注意,一張表是不是一個序列和它的非數字鍵無關。

3.4.8 – 優先級

Lua 中操做符的優先級寫在下表中,從低到高優先級排序:

     or
     and
     <     >     <=    >=    ~=    ==
     |
     ~
     &
     <<    >>
     ..
     +     -
     *     /     //    %
     unary operators (not   #     -     ~)
     ^

一般, 你能夠用括號來改變運算次序。 鏈接操做符 ('..') 和乘方操做 ('^') 是從右至左的。 其它全部的操做都是從左至右。

3.4.9 – 表構建

表構造子是一個構造表的表達式。 每次構造子被執行,都會構造出一張新的表。 構造子能夠被用來構造一張空表, 也能夠用來構造一張表並初始化其中的一些域。 通常的構造子的語法以下

	tableconstructor ::= ‘{’ [fieldlist] ‘}’
	fieldlist ::= field {fieldsep field} [fieldsep]
	field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp
	fieldsep ::= ‘,’ | ‘;

每一個形如 [exp1] = exp2 的域向表中增長新的一項, 其鍵爲 exp1 而值爲 exp2。 形如 name = exp 的域等價於 ["name"] = exp。 最後,形如 exp 的域等價於 [i] = exp, 這裏的 i 是一個從 1 開始不斷增加的數字。 這這個格式中的其它域不會破壞其記數。 舉個例子:

     a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }

等價於

     do
       local t = {}
       t[f(1)] = g
       t[1] = "x"         -- 1st exp
       t[2] = "y"         -- 2nd exp
       t.x = 1            -- t["x"] = 1
       t[3] = f(x)        -- 3rd exp
       t[30] = 23
       t[4] = 45          -- 4th exp
       a = t
     end

構造子中賦值的次序未定義。 (次序問題只會對那些鍵重複時的狀況有影響。)

若是表單中最後一個域的形式是 exp , 並且其表達式是一個函數調用或者是一個可變參數, 那麼這個表達式全部的返回值將依次進入列表 (參見 §3.4.10)。

初始化域表能夠在最後多一個分割符, 這樣設計能夠方便由機器生成代碼。

3.4.10 – 函數調用

Lua 中的函數調用的語法以下:

	functioncall ::= prefixexp args

函數調用時, 第一步,prefixexp 和 args 先被求值。 若是 prefixexp 的值的類型是 function, 那麼這個函數就被用給出的參數調用。 不然 prefixexp 的元方法 "call" 就被調用, 第一個參數是 prefixexp 的值, 接下來的是原來的調用參數 (參見 §2.4)。

這樣的形式

	functioncall ::= prefixexp ‘:’ Name args

能夠用來調用 "方法"。 這是 Lua 支持的一種語法糖。 像 v:name(args) 這個樣子, 被解釋成 v.name(v,args), 這裏的 v 只會被求值一次。

參數的語法以下:

	args ::= ‘(’ [explist] ‘)’
	args ::= tableconstructor
	args ::= LiteralString

全部參數的表達式求值都在函數調用以前。 這樣的調用形式 f{fields} 是一種語法糖用於表示 f({fields}); 這裏指參數列表是一個新建立出來的列表。 而這樣的形式 f'string'(或是 f"string" 亦或是 f[[string]]) 也是一種語法糖,用於表示 f('string'); 此時的參數列表是一個單獨的字符串。

return functioncall 這樣的調用形式將觸發一次 尾調用。 Lua 實現了 徹底尾調用(或稱爲 徹底尾遞歸): 在尾調用中, 被調用的函數重用調用它的函數的堆棧項。 所以,對於程序執行的嵌套尾調用的層數是沒有限制的。 然而,尾調用將刪除調用它的函數的任何調試信息。 注意,尾調用只發生在特定的語法下, 僅當 return 只有單一函數調用做爲參數時才發生尾調用; 這種語法使得調用函數的全部結果能夠完整地返回。 所以,下面這些例子都不是尾調用:

     return (f(x))        -- 返回值被調整爲一個
     return 2 * f(x)
     return x, f(x)       -- 追加若干返回值
     f(x); return         -- 返回值所有被捨棄
     return x or f(x)     -- 返回值被調整爲一個

3.4.11 – 函數定義

函數定義的語法以下:

	functiondef ::= function funcbody
	funcbody ::= ‘(’ [parlist] ‘)’ block end

另外定義了一些語法糖簡化函數定義的寫法:

	stat ::= function funcname funcbody
	stat ::= local function Name funcbody
	funcname ::= Name {‘.’ Name} [‘:’ Name]

該語句

     function f () body end

被轉譯成

     f = function () body end

該語句

     function t.a.b.c.f () body end

被轉譯成

     t.a.b.c.f = function () body end

該語句

     local function f () body end

被轉譯成

     local f; f = function () body end

而不是

     local f = function () body end

(這個差異只在函數體內須要引用 f 時纔有。)

一個函數定義是一個可執行的表達式, 執行結果是一個類型爲 function 的值。 當 Lua 預編譯一個代碼塊時, 代碼塊做爲一個函數,整個函數體也就被預編譯了。 那麼,不管什麼時候 Lua 執行了函數定義, 這個函數自己就進行了 實例化(或者說是 關閉了)。 這個函數的實例(或者說是 閉包)是表達式的最終值。

形參被看做是一些局部變量, 它們將由實參的值來初始化:

	parlist ::= namelist [‘,’ ‘...’] | ‘...

當一個函數被調用, 若是函數並不是一個 可變參數函數, 即在形參列表的末尾註明三個點 ('...'), 那麼實參列表就會被調整到形參列表的長度。 變長參數函數不會調整實參列表; 取而代之的是,它將把全部額外的參數放在一塊兒經過 變長參數表達式傳遞給函數, 其寫法依舊是三個點。 這個表達式的值是一串實參值的列表, 看起來就跟一個能夠返回多個結果的函數同樣。 若是一個變長參數表達式放在另外一個表達式中使用, 或是放在另外一串表達式的中間, 那麼它的返回值就會被調整爲單個值。 若這個表達式放在了一系列表達式的最後一個, 就不會作調整了 (除非這最後一個參數被括號給括了起來)。

咱們先作以下定義,而後再來看一個例子:

     function f(a, b) end
     function g(a, b, ...) end
     function r() return 1,2,3 end

下面看看實參到形參數以及可變長參數的映射關係:

     CALL            PARAMETERS
     
     f(3)             a=3, b=nil
     f(3, 4)          a=3, b=4
     f(3, 4, 5)       a=3, b=4
     f(r(), 10)       a=1, b=10
     f(r())           a=1, b=2
     
     g(3)             a=3, b=nil, ... -->  (nothing)
     g(3, 4)          a=3, b=4,   ... -->  (nothing)
     g(3, 4, 5, 8)    a=3, b=4,   ... -->  5  8
     g(5, r())        a=5, b=1,   ... -->  2  3

結果由 return 來返回(參見 §3.3.4)。 若是執行到函數末尾依舊沒有遇到任何 return 語句, 函數就不會返回任何結果。

關於函數可返回值的數量限制和系統有關。 這個限制必定大於 1000 。

冒號 語法能夠用來定義 方法, 就是說,函數能夠有一個隱式的形參 self。 所以,以下語句

     function t.a.b.c:f (params) body end

是這樣一種寫法的語法糖

     t.a.b.c.f = function (self, params) body end

3.5 – 可見性規則

Lua 語言有詞法做用範圍。 變量的做用範圍開始於聲明它們以後的第一個語句段, 結束於包含這個聲明的最內層語句塊的最後一個非空語句。 看下面這些例子:

     x = 10                -- 全局變量
     do                    -- 新的語句塊
       local x = x         -- 新的一個 'x', 它的值如今是 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 正在被聲明,可是尚未進入它的做用範圍, 因此第二個 x 指向的是外面一層的變量。

由於有這樣一個詞法做用範圍的規則, 局部變量能夠被在它的做用範圍內定義的函數自由使用。 當一個局部變量被內層的函數中使用的時候, 它被內層函數稱做 上值,或是 外部局部變量

注意,每次執行到一個 local 語句都會定義出一個新的局部變量。 看看這樣一個例子:

     a = {}
     local x = 20
     for i=1,10 do
       local y = 0
       a[i] = function () y=y+1; return x+y end
     end

這個循環建立了十個閉包(這指十個匿名函數的實例)。 這些閉包中的每個都使用了不一樣的 y 變量, 而它們又共享了同一份 x

4 – 編程接口

這個部分描述了 Lua 的 C API , 也就是宿主程序跟 Lua 通信用的一組 C 函數。 全部的 API 函數按相關的類型以及常量都聲明在頭文件 lua.h 中。

雖然咱們說的是「函數」, 但一部分簡單的 API 是以宏的形式提供的。 除非另有說明, 全部的這些宏都只使用它們的參數一次 (除了第一個參數,那必定是 Lua 狀態), 所以你不需擔憂這些宏的展開會引發一些反作用。

C 庫中全部的 Lua API 函數都不去檢查參數是否相容及有效。 然而,你能夠在編譯 Lua 時加上打開一個宏開關 LUA_USE_APICHECK 來改變這個行爲。

4.1 – 

Lua 使用一個 虛擬棧 來和 C 互傳值。 棧上的的每一個元素都是一個 Lua 值 (nil,數字,字符串,等等)。

不管什麼時候 Lua 調用 C,被調用的函數都獲得一個新的棧, 這個棧獨立於 C 函數自己的棧,也獨立於以前的 Lua 棧。 它裏面包含了 Lua 傳遞給 C 函數的全部參數, 而 C 函數則把要返回的結果放入這個棧以返回給調用者 (參見 lua_CFunction)。

方便起見, 全部針對棧的 API 查詢操做都不嚴格遵循棧的操做規則。 而是能夠用一個 索引 來指向棧上的任何元素: 正的索引指的是棧上的絕對位置(從1開始); 負的索引則指從棧頂開始的偏移量。 展開來講,若是堆棧有 n 個元素, 那麼索引 1 表示第一個元素 (也就是最早被壓棧的元素) 而索引 n 則指最後一個元素; 索引 -1 也是指最後一個元素 (即棧頂的元素), 索引 -n 是指第一個元素。

4.2 – 棧大小

當你使用 Lua API 時, 就有責任保證作恰當的調用。 特別須要注意的是, 你有責任控制不要堆棧溢出。 你能夠使用 lua_checkstack 這個函數來擴大可用堆棧的尺寸。

不管什麼時候 Lua 調用 C , 它都只保證至少有 LUA_MINSTACK 這麼多的堆棧空間能夠使用。 LUA_MINSTACK 通常被定義爲 20 , 所以,只要你不是不斷的把數據壓棧, 一般你不用關心堆棧大小。

當你調用一個 Lua 函數卻沒有指定要接收多少個返回值時 (參見 lua_call), Lua 能夠保證棧必定有足夠的空間來接收全部的返回值, 但不保證此外留有額外的空間。 所以,在作了一次這樣的調用後,若是你須要繼續壓棧, 則須要使用 lua_checkstack

4.3 – 有效索引與可接受索引

API 中的函數若須要傳入棧索引,這個索引必須是 有效索引 或是 可接受索引

有效索引 指引用棧內真實位置的索引; 即在 1 到棧頂之間的位置 (1 ≤ abs(index) ≤ top)。 一般,一個可能修改該位置的值的函數須要傳入有效索引。

除非另有說明, 任何能夠接受有效索引的函數同時也接受 僞索引。 僞索引指代一些能夠被 C code 訪問獲得 Lua 值,而它們又不在棧內。 這用於訪問註冊表以及 C 函數的上值(參見 §4.4)。

對於那些只是須要棧中的值(例如查詢函數) 而不須要指定一個棧位置的函數, 能夠用一個可接受的索引去調用它們。 可接受索引 不只能夠是任何包括僞索引在內的有效索引, 還能夠是任何超過棧頂但落在爲棧分配出來的空間內的正索引。 (注意 0 永遠都不是一個可接受索引。) 除非另有說明,API 裏的函數都接受可接受索引。

容許可接受索引是爲了不對棧頂之外的查詢時作額外的檢查。 例如,C 函數能夠直接查詢傳給它的第三個參數, 而不用先檢查是否是有第三個參數, 即不須要檢查 3 是否是一個有效索引。

對於那些以可接受索引調用的函數, 無效索引被看做包含了一個虛擬類型 LUA_TNONE 的值, 這個值的行爲和 nil 一致。

4.4 – C 閉包

當 C 函數被建立出來, 咱們有可能會把一些值關聯在一塊兒, 也就是建立一個 C 閉包 (參見 lua_pushcclosure); 這些被關聯起來的值被叫作 上值 , 它們能夠在函數被調用的時候訪問的到。

不管什麼時候去調用 C 函數, 函數的上值均可以用僞索引定位。 咱們能夠用 lua_upvalueindex 這個宏來生成這些僞索引。 第一個關聯到函數的值放在 lua_upvalueindex(1) 位置處,依此類推。 使用 lua_upvalueindex(n) 時, 若 n 大於當前函數的總上值個數 (但不能夠大於 256)會產生一個可接受的但無效的索引。

4.5 – 註冊表

Lua 提供了一個 註冊表, 這是一個預約義出來的表, 能夠用來保存任何 C 代碼想保存的 Lua 值。 這個表能夠用有效僞索引 LUA_REGISTRYINDEX 來定位。 任何 C 庫均可以在這張表裏保存數據, 爲了防止衝突,你須要特別當心的選擇鍵名。 通常的用法是,你能夠用一個包含你的庫名的字符串作爲鍵名, 或者取你本身 C 對象的地址,以輕量用戶數據的形式作鍵, 還能夠用你的代碼建立出來的任意 Lua 對象作鍵。 關於變量名,字符串鍵名中如下劃線加大寫字母的名字被 Lua 保留。

註冊表中的整數鍵用於引用機制 (參見 luaL_ref), 以及一些預約義的值。 所以,整數鍵不要用於別的目的。

當你建立了一個新的 Lua 狀態機, 其中的註冊表內就預約義好了幾個值。 這些預約義值能夠用整數索引到, 這些整數以常數形式定義在 lua.h 中。 有下列常數:

  • LUA_RIDX_MAINTHREAD註冊表中這個索引下是狀態機的主線程。 (主線程和狀態機同時被建立出來。)
  • LUA_RIDX_GLOBALS註冊表的這個索引下是全局環境。

4.6 – C 中的錯誤處理

在內部實現中,Lua 使用了 C 的 longjmp 機制來處理錯誤。 (若是你使用 C++ 編譯,Lua 將換成異常; 細節請在源代碼中搜索 LUAI_THROW。) 當 Lua 碰到任何錯誤 (好比內存分配錯誤、類型錯誤、語法錯誤、還有運行時錯誤) 它都會 拋出一個錯誤出去; 也就是調用一次長跳轉。 在 保護環境 下, Lua 使用 setjmp 來設置一個恢復點; 任何發生的錯誤都會跳轉到最近的一個恢復點。

若是錯誤發生在保護環境以外, Lua 會先調用 panic 函數 (參見 lua_atpanic) 而後調用 abort 來退出宿主程序。 你的 panic 函數只要不返回 (例如:長跳轉到你在 Lua 外你本身設置的恢復點) 就能夠不退出程序。

panic 函數以錯誤消息處理器(參見 §2.3)的方式運行; 錯誤消息在棧頂。 不一樣的是,它不保證棧空間。 作任何壓棧操做前,panic 函數都必須先檢查是否有足夠的空間 (參見§4.2)。

大多數 API 函數都有可能拋出錯誤, 例如在內存分配錯誤時就會拋出。 每一個函數的文檔都會註明它是否可能拋出錯誤。

在 C 函數內部,你能夠經過調用 lua_error 來拋出錯誤。

4.7 – C 中的讓出處理

Lua 內部使用 C 的 longjmp 機制讓出一個協程。 所以,若是一個 C 函數 foo 調用了一個 API 函數, 而這個 API 函數讓出了(直接或間接調用了讓出函數)。 因爲 longjmp 會移除 C 棧的棧幀, Lua 就沒法返回到 foo 裏了。

爲了迴避這類問題, 碰到 API 調用中調用讓出時,除了那些拋出錯誤的 API 外,還提供了三個函數: lua_yieldk, lua_callk,和 lua_pcallk 。 它們在讓出發生時,能夠從傳入的 延續函數 (名爲 k 的參數)繼續運行。

咱們須要預設一些術語來解釋延續點。 對於從 Lua 中調用的 C 函數,咱們稱之爲 原函數。 從這個原函數中調用的上面所述的三個 C API 函數咱們稱之爲 被調函數。 被調函數能夠使當前線程讓出。 (讓出發生在被調函數是 lua_yieldk, 或傳入 lua_callk 或 lua_pcallk 的函數調用了讓出時。)

假設正在運行的線程在執行被調函數時讓出。 當再次延續這條線程,它但願繼續被調函數的運行。 然而,被調函數不可能返回到原函數中。 這是由於以前的讓出操做破壞了 C 棧的棧幀。 做爲替代品,Lua 調用那個做爲被調函數參數給出的 延續函數 。 正如其名,延續函數將延續原函數的任務。

下面的函數會作一個說明:

     int original_function (lua_State *L) {
       ...     /* code 1 */
       status = lua_pcall(L, n, m, h);  /* calls Lua */
       ...     /* code 2 */
     }

如今咱們想容許被 lua_pcall 運行的 Lua 代碼讓出。 首先,咱們把函數改寫成這個樣子:

     int k (lua_State *L, int status, lua_KContext ctx) {
       ...  /* code 2 */
     }
     
     int original_function (lua_State *L) {
       ...     /* code 1 */
       return k(L, lua_pcall(L, n, m, h), ctx);
     }

上面的代碼中,新函數 k 就是一個 延續函數 (函數類型爲 lua_KFunction)。 它的工做就是原函數中調用 lua_pcall 以後作的那些事情。 如今咱們必須通知 Lua 說,你必須在被 lua_pcall 執行的 Lua 代碼發生過中斷(錯誤或讓出)後, 還得繼續調用 k 。 因此咱們還得繼續改寫這段代碼,把 lua_pcall 替換成 lua_pcallk

     int original_function (lua_State *L) {
       ...     /* code 1 */
       return k(L, lua_pcallk(L, n, m, h, ctx2, k), ctx1);
     }

注意這裏那個額外的顯式的對延續函數的調用: Lua 僅在須要時,這多是由錯誤致使的也多是發生了讓出而須要繼續運行,纔會調用延續函數。 若是沒有發生過任何讓出,調用的函數正常返回, 那麼 lua_pcallk (以及 lua_callk)也會正常返回。 (固然,這個例子中你也能夠不在以後調用延續函數, 而是在原函數的調用後直接寫上須要作的工做。)

除了 Lua 狀態,延續函數還有兩個參數: 一個是調用最後的狀態碼,另外一個一開始由 lua_pcallk 傳入的上下文 (ctx)。 (Lua 自己不使用這個值;它僅僅從原函數轉發這個值給延續函數。) 對於 lua_pcallk 而言, 狀態碼和 lua_pcallk 本應返回值相同,區別僅在於發生過讓出後才執行完時,狀態碼爲 LUA_YIELD(而不是 LUA_OK)。 對於lua_yieldk 和 lua_callk 而言, 調用延續函數傳入的狀態碼必定是 LUA_YIELD。 (對這兩個函數,Lua 不會因任何錯誤而調用延續函數。 由於它們並不處理錯誤。) 一樣,當你使用 lua_callk 時, 你應該用 LUA_OK 做爲狀態碼來調用延續函數。 (對於 lua_yieldk, 幾乎沒有什麼地方須要直接調用延續函數, 由於 lua_yieldk 自己並不會返回。)

Lua 會把延續函數看做原函數。 延續函數將接收到和原函數相同的 Lua 棧,其接收到的 lua 狀態也和 被調函數若返回後應該有的狀態一致。 (例如, lua_callk 調用以後, 棧中以前壓入的函數和調用參數都被調用產生的返回值所替代。) 這時也有相同的上值。 等到它返回的時候,Lua 會將其看待成原函數的返回去操做。

4.8 – 函數和類型

這裏按字母次序列出了全部 C API 中的函數和類型。 每一個函數都有一個這樣的提示:[-o, +p, x]

對於第一個域,o, 指的是該函數會從棧上彈出多少個元素。 第二個域,p, 指該函數會將多少個元素壓棧。 (全部函數都會在彈出參數後再把結果壓棧。) x|y 這種形式的域表示該函數根據具體狀況可能壓入(或彈出) x 或 y 個元素; 問號 '?' 表示 咱們沒法僅經過參數來了解該函數會彈出/壓入多少元素 (好比,數量取決於棧上有些什麼)。 第三個域,x, 解釋了該函數是否會拋出錯誤: '-' 表示該函數絕對不會拋出錯誤; 'e' 表示該函數可能拋出錯誤; 'v' 表示該函數可能拋出有意義的錯誤。

lua_absindex

[-0, +0, –]

int lua_absindex (lua_State *L, int idx);

將一個可接受的索引 idx 轉換爲絕對索引 (即,一個不依賴棧頂在哪的值)。

lua_Alloc

typedef void * (*lua_Alloc) (void *ud,
                             void *ptr,
                             size_t osize,
                             size_t nsize);

Lua 狀態機中使用的內存分配器函數的類型。 內存分配函數必須提供一個功能相似於 realloc 但又不徹底相同的函數。 它的參數有 ud ,一個由 lua_newstate 傳給它的指針;ptr ,一個指向已分配出來/將被從新分配/要釋放的內存塊指針; osize ,內存塊原來的尺寸或是關於什麼將被分配出來的代碼; nsize ,新內存塊的尺寸。

若是 ptr 不是 NULL, osize 是 ptr 指向的內存塊的尺寸, 即這個內存塊當初被分配或重分配的尺寸。

若是 ptr 是 NULL, osize 是 Lua 即將分配對象類型的編碼。 當(且僅當)Lua 建立一個對應類型的新對象時, osize 是LUA_TSTRINGLUA_TTABLELUA_TFUNCTION, LUA_TUSERDATA,或 LUA_TTHREAD 中的一個。 若 osize 是其它類型,Lua 將爲其它東西分配內存。

Lua 假定分配器函數會遵循如下行爲:

當 nsize 是零時, 分配器必須和 free 行爲相似並返回 NULL

當 nsize 不是零時, 分配器必須和 realloc 行爲相似。 若是分配器沒法完成請求,返回 NULL。 Lua 假定在 osize >= nsize 成立的條件下, 分配器毫不會失敗。

這裏有一個簡單的分配器函數的實現。 這個實現被放在補充庫中,供 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);
     }

注意,標準 C 能確保 free(NULL) 沒有反作用, 且 realloc(NULL,size) 等價於 malloc(size)。 這段代碼假定 realloc 在縮小塊長度時不會失敗。 (雖然標準 C 沒有對此行爲作出保證,但這看起來是一個安全的假定。)

lua_arith

[-(2|1), +1, e]

void lua_arith (lua_State *L, int op);

對棧頂的兩個值(或者一個,好比取反)作一次數學或位操做。 其中,棧頂的那個值是第二個操做數。 它會彈出壓入的值,並把結果放在棧頂。 這個函數遵循 Lua 對應的操做符運算規則 (即有可能觸發元方法)。

op 的值必須是下列常量中的一個:

  • LUA_OPADD加法 (+)
  • LUA_OPSUB減法 (-)
  • LUA_OPMUL乘法 (*)
  • LUA_OPDIV浮點除法 (/)
  • LUA_OPIDIV向下取整的除法 (//)
  • LUA_OPMOD取模 (%)
  • LUA_OPPOW乘方 (^)
  • LUA_OPUNM取負 (一元 -)
  • LUA_OPBNOT按位取反 (~)
  • LUA_OPBAND按位與 (&)
  • LUA_OPBOR按位或 (|)
  • LUA_OPBXOR按位異或 (~)
  • LUA_OPSHL左移 (<<)
  • LUA_OPSHR右移 (>>)

lua_atpanic

[-0, +0, –]

lua_CFunction lua_atpanic (lua_State *L, lua_CFunction panicf);

設置一個新的 panic 函數,並返回以前設置的那個。 (參見 §4.6)。

lua_call

[-(nargs+1), +nresults, e]

void lua_call (lua_State *L, int nargs, int nresults);

調用一個函數。

要調用一個函數請遵循如下協議: 首先,要調用的函數應該被壓入棧; 接着,把須要傳遞給這個函數的參數按正序壓棧; 這是指第一個參數首先壓棧。 最後調用一下 lua_callnargs 是你壓入棧的參數個數。 當函數調用完畢後,全部的參數以及函數自己都會出棧。 而函數的返回值這時則被壓棧。 返回值的個數將被調整爲 nresults 個, 除非 nresults被設置成 LUA_MULTRET。 在這種狀況下,全部的返回值都被壓入堆棧中。 Lua 會保證返回值都放入棧空間中。 函數返回值將按正序壓棧(第一個返回值首先壓棧), 所以在調用結束後,最後一個返回值將被放在棧頂。

被調用函數內發生的錯誤將(經過 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' */

注意上面這段代碼是 平衡 的: 到了最後,堆棧恢復成原有的配置。 這是一種良好的編程習慣。

lua_callk

[-(nargs + 1), +nresults, e]

void lua_callk (lua_State *L,
                int nargs,
                int nresults,
                lua_KContext ctx,
                lua_KFunction k);

這個函數的行爲和 lua_call 徹底一致,只不過它還容許被調用的函數讓出 (參見 §4.7)。

lua_CFunction

typedef int (*lua_CFunction) (lua_State *L);

C 函數的類型。

爲了正確的和 Lua 通信, C 函數必須使用下列協議。 這個協議定義了參數以及返回值傳遞方法: C 函數經過 Lua 中的棧來接受參數, 參數以正序入棧(第一個參數首先入棧)。 所以,當函數開始的時候, lua_gettop(L) 能夠返回函數收到的參數個數。 第一個參數(若是有的話)在索引 1 的地方, 而最後一個參數在索引 lua_gettop(L) 處。 當須要向 Lua 返回值的時候, C 函數只須要把它們以正序壓到堆棧上(第一個返回值最早壓入), 而後返回這些返回值的個數。 在這些返回值之下的,堆棧上的東西都會被 Lua 丟掉。 和 Lua 函數同樣,從 Lua 中調用 C 函數也能夠有不少返回值。

下面這個例子中的函數將接收若干數字參數,並返回它們的平均數與和:

     static int foo (lua_State *L) {
       int n = lua_gettop(L);    /* 參數的個數 */
       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;                   /* 返回值的個數 */
     }

lua_checkstack

[-0, +0, –]

int lua_checkstack (lua_State *L, int n);

確保堆棧上至少有 n 個額外空位。 若是不能把堆棧擴展到相應的尺寸,函數返回假。 失敗的緣由包括將把棧擴展到比固定最大尺寸還大 (至少是幾千個元素)或分配內存失敗。 這個函數永遠不會縮小堆棧; 若是堆棧已經比須要的大了,那麼就保持原樣。

lua_close

[-0, +0, –]

void lua_close (lua_State *L);

銷燬指定 Lua 狀態機中的全部對象 (若是有垃圾收集相關的元方法的話,會調用它們), 而且釋放狀態機中使用的全部動態內存。 在一些平臺上,你能夠沒必要調用這個函數, 由於當宿主程序結束的時候,全部的資源就天然被釋放掉了。 另外一方面,長期運行的程序,好比一個後臺程序或是一個網站服務器, 會建立出多個 Lua 狀態機。那麼就應該在不須要時趕忙關閉它們。

lua_compare

[-0, +0, e]

int lua_compare (lua_State *L, int index1, int index2, int op);

比較兩個 Lua 值。 當索引 index1 處的值經過 op 和索引 index2 處的值作比較後條件知足,函數返回 1 。 這個函數遵循 Lua 對應的操做規則(即有可能觸發元方法)。 反之,函數返回 0。 當任何一個索引無效時,函數也會返回 0 。

op 值必須是下列常量中的一個:

  • LUA_OPEQ相等比較 (==)
  • LUA_OPLT小於比較 (<)
  • LUA_OPLE小於等於比較 (<=)

lua_concat

[-n, +1, e]

void lua_concat (lua_State *L, int n);

鏈接棧頂的 n 個值, 而後將這些值出棧,並把結果放在棧頂。 若是 n 爲 1 ,結果就是那個值放在棧上(即,函數什麼都不作); 若是 n 爲 0 ,結果是一個空串。 鏈接依照 Lua 中一般語義完成(參見 §3.4.6 )。

lua_copy

[-0, +0, –]

void lua_copy (lua_State *L, int fromidx, int toidx);

從索引 fromidx 處複製一個值到一個有效索引 toidx 處,覆蓋那裏的原有值。 不會影響其它位置的值。

lua_createtable

[-0, +1, e]

void lua_createtable (lua_State *L, int narr, int nrec);

建立一張新的空表壓棧。 參數 narr 建議了這張表做爲序列使用時會有多少個元素; 參數 nrec 建議了這張表可能擁有多少序列以外的元素。 Lua 會使用這些建議來預分配這張新表。 若是你知道這張表用途的更多信息,預分配能夠提升性能。 不然,你能夠使用函數 lua_newtable 。

lua_dump

[-0, +0, e]

int lua_dump (lua_State *L,
                        lua_Writer writer,
                        void *data,
                        int strip);

把函數導出成二進制代碼塊 。 函數接收棧頂的 Lua 函數作參數, 而後生成它的二進制代碼塊。 若被導出的東西被再次加載, 加載的結果就至關於原來的函數。 當它在產生代碼塊的時候, lua_dump 經過調用函數 writer (參見 lua_Writer ) 來寫入數據,後面的 data 參數會被傳入 writer 。

若是 strip 爲真, 二進制代碼塊將不包含該函數的調試信息。

最後一次由 writer 的返回值將做爲這個函數的返回值返回; 0 表示沒有錯誤。

該函數不會把 Lua 函數彈出堆棧。

lua_error

[-1, +0, v]

int lua_error (lua_State *L);

以棧頂的值做爲錯誤對象,拋出一個 Lua 錯誤。 這個函數將作一次長跳轉,因此必定不會返回 (參見 luaL_error)。

lua_gc

[-0, +0, e]

int lua_gc (lua_State *L, int what, int data);

控制垃圾收集器。

這個函數根據其參數 what 發起幾種不一樣的任務:

  • LUA_GCSTOP中止垃圾收集器。
  • LUA_GCRESTART重啓垃圾收集器。
  • LUA_GCCOLLECT發起一次完整的垃圾收集循環。
  • LUA_GCCOUNT返回 Lua 使用的內存總量(以 K 字節爲單位)。
  • LUA_GCCOUNTB返回當前內存使用量除以 1024 的餘數。
  • LUA_GCSTEP發起一步增量垃圾收集。
  • LUA_GCSETPAUSE把 data 設爲 垃圾收集器間歇率 (參見 §2.5),並返回以前設置的值。
  • LUA_GCSETSTEPMUL把 data 設爲 垃圾收集器步進倍率 (參見 §2.5),並返回以前設置的值。
  • LUA_GCISRUNNING返回收集器是否在運行(即沒有中止)。

關於這些選項的細節,參見 collectgarbage 。

lua_getallocf

[-0, +0, –]

lua_Alloc lua_getallocf (lua_State *L, void **ud);

返回給定狀態機的內存分配器函數。 若是 ud 不是 NULL , Lua 把設置內存分配函數時設置的那個指針置入 *ud 。

lua_getfield

[-0, +1, e]

int lua_getfield (lua_State *L, int index, const char *k);

把 t[k] 的值壓棧, 這裏的 t 是索引指向的值。 在 Lua 中,這個函數可能觸發對應 "index" 事件對應的元方法 (參見 §2.4 )。

函數將返回壓入值的類型。

lua_getextraspace

[-0, +0, –]

void *lua_getextraspace (lua_State *L);

返回一個 Lua 狀態機中關聯的內存塊指針。 程序能夠把這塊內存用於任何用途;而 Lua 不會使用它。

每個新線程都會攜帶一塊內存, 初始化爲主線程的這塊內存的副本。

默認配置下,這塊內存的大小爲空指針的大小。 不過你能夠從新編譯 Lua 設定這塊內存不一樣的大小。 (參見 luaconf.h 中的 LUA_EXTRASPACE。)

lua_getglobal

[-0, +1, e]

int lua_getglobal (lua_State *L, const char *name);

把全局變量 name 裏的值壓棧,返回該值的類型。

lua_geti

[-0, +1, e]

int lua_geti (lua_State *L, int index, lua_Integer i);

把 t[i] 的值壓棧, 這裏的 t 指給定的索引指代的值。 和在 Lua 裏同樣,這個函數可能會觸發 "index" 事件的元方法 (參見 §2.4)。

返回壓入值的類型。

lua_getmetatable

[-0, +(0|1), –]

int lua_getmetatable (lua_State *L, int index);

若是該索引處的值有元表,則將其元表壓棧,返回 1 。 不然不會將任何東西入棧,返回 0 。

lua_gettable

[-1, +1, e]

int lua_gettable (lua_State *L, int index);

把 t[k] 的值壓棧, 這裏的 t 是指索引指向的值, 而 k 則是棧頂放的值。

這個函數會彈出堆棧上的鍵,把結果放在棧上相同位置。 和在 Lua 中同樣, 這個函數可能觸發對應 "index" 事件的元方法 (參見 §2.4 )。

返回壓入值的類型。

lua_gettop

[-0, +0, –]

int lua_gettop (lua_State *L);

返回棧頂元素的索引。 由於索引是從 1 開始編號的, 因此這個結果等於棧上的元素個數; 特別指出,0 表示棧爲空。

lua_getuservalue

[-0, +1, –]

int lua_getuservalue (lua_State *L, int index);

將給定索引處的用戶數據所關聯的 Lua 值壓棧。

返回壓入值的類型。

lua_insert

[-1, +1, –]

void lua_insert (lua_State *L, int index);

把棧頂元素移動到指定的有效索引處, 依次移動這個索引之上的元素。 不要用僞索引來調用這個函數, 由於僞索引沒有真正指向棧上的位置。

lua_Integer

typedef ... lua_Integer;

Lua 中的整數類型。

缺省時,這個就是 long long, (一般是一個 64 位以二爲補碼的整數), 也能夠修改它爲 long 或 int (一般是一個 32 位以二爲補碼的整數)。 (參見 luaconf.h 中的LUA_INT 。)

Lua 定義了兩個常量: LUA_MININTEGER 和 LUA_MAXINTEGER 來表示這個類型能夠表示的最小和最大值。

lua_isboolean

[-0, +0, –]

int lua_isboolean (lua_State *L, int index);

當給定索引的值是一個布爾量時,返回 1 ,不然返回 0 。

lua_iscfunction

[-0, +0, –]

int lua_iscfunction (lua_State *L, int index);

當給定索引的值是一個 C 函數時,返回 1 ,不然返回 0 。

lua_isfunction

[-0, +0, –]

int lua_isfunction (lua_State *L, int index);

當給定索引的值是一個函數( C 或 Lua 函數都可)時,返回 1 ,不然返回 0 。

lua_isinteger

[-0, +0, –]

int lua_isinteger (lua_State *L, int index);

當給定索引的值是一個整數 (其值是一個數字,且內部以整數儲存), 時,返回 1 ,不然返回 0 。

lua_islightuserdata

[-0, +0, –]

int lua_islightuserdata (lua_State *L, int index);

當給定索引的值是一個輕量用戶數據時,返回 1 ,不然返回 0 。

lua_isnil

[-0, +0, –]

int lua_isnil (lua_State *L, int index);

當給定索引的值是 nil 時,返回 1 ,不然返回 0 。

lua_isnone

[-0, +0, –]

int lua_isnone (lua_State *L, int index);

當給定索引無效時,返回 1 ,不然返回 0 。

lua_isnoneornil

[-0, +0, –]

int lua_isnoneornil (lua_State *L, int index);

當給定索引無效或其值是 nil 時, 返回 1 ,不然返回 0 。

lua_isnumber

[-0, +0, –]

int lua_isnumber (lua_State *L, int index);

當給定索引的值是一個數字,或是一個可轉換爲數字的字符串時,返回 1 ,不然返回 0 。

lua_isstring

[-0, +0, –]

int lua_isstring (lua_State *L, int index);

當給定索引的值是一個字符串或是一個數字 (數字總能轉換成字符串)時,返回 1 ,不然返回 0 。

lua_istable

[-0, +0, –]

int lua_istable (lua_State *L, int index);

當給定索引的值是一張表時,返回 1 ,不然返回 0 。

lua_isthread

[-0, +0, –]

int lua_isthread (lua_State *L, int index);

當給定索引的值是一條線程時,返回 1 ,不然返回 0 。

lua_isuserdata

[-0, +0, –]

int lua_isuserdata (lua_State *L, int index);

當給定索引的值是一個用戶數據(不管是徹底的仍是輕量的)時, 返回 1 ,不然返回 0 。

lua_isyieldable

[-0, +0, –]

int lua_isyieldable (lua_State *L);

若是給定的協程可讓出,返回 1 ,不然返回 0 。

lua_KContext

typedef ... lua_KContext;

延續函數上下文參數的類型。 這必定是一個數字類型。 當有 intptr_t 時,被定義爲 intptr_t , 所以它也能夠保存指針。 不然,它被定義爲 ptrdiff_t

lua_KFunction

typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx);

延續函數的類型(參見 §4.7 )。

lua_len

[-0, +1, e]

void lua_len (lua_State *L, int index);

返回給定索引的值的長度。 它等價於 Lua 中的 '#' 操做符 (參見 §3.4.7)。 它有可能觸發 "length" 事件對應的元方法 (參見 §2.4 )。 結果壓棧。

lua_load

[-0, +1, –]

int lua_load (lua_State *L,
              lua_Reader reader,
              void *data,
              const char *chunkname,
              const char *mode);

加載一段 Lua 代碼塊,但不運行它。 若是沒有錯誤, lua_load 把一個編譯好的代碼塊做爲一個 Lua 函數壓到棧頂。 不然,壓入錯誤消息。

lua_load 的返回值能夠是:

  • LUA_OK沒有錯誤;
  • LUA_ERRSYNTAX在預編譯時碰到語法錯誤;
  • LUA_ERRMEM內存分配錯誤;
  • LUA_ERRGCMM在運行 __gc 元方法時出錯了。 (這個錯誤和代碼塊加載過程無關,它是由垃圾收集器引起的。)

lua_load 函數使用一個用戶提供的 reader 函數來讀取代碼塊(參見 lua_Reader )。 data 參數會被傳入 reader 函數。

chunkname 這個參數能夠賦予代碼塊一個名字, 這個名字被用於出錯信息和調試信息(參見 §4.9)。

lua_load 會自動檢測代碼塊是文本的仍是二進制的, 而後作對應的加載操做(參見程序 luac )。 字符串 mode 的做用和函數 load 一致。 它還能夠是 NULL 等價於字符串 "bt"。

lua_load 的內部會使用棧, 所以 reader 函數必須永遠在每次返回時保留棧的原樣。

若是返回的函數有上值, 第一個上值會被設置爲 保存在註冊表(參見 §4.5) LUA_RIDX_GLOBALS 索引處的全局環境。 在加載主代碼塊時,這個上值是 _ENV 變量(參見§2.2)。 其它上值均被初始化爲 nil

lua_newstate

[-0, +0, –]

lua_State *lua_newstate (lua_Alloc f, void *ud);

建立一個運行在新的獨立的狀態機中的線程。 若是沒法建立線程或狀態機(因爲內存有限)則返回 NULL。 參數 f 是一個分配器函數; Lua 將經過這個函數作狀態機內全部的內存分配操做。 第二個參數 ud ,這個指針將在每次調用分配器時被轉入。

lua_newtable

[-0, +1, e]

void lua_newtable (lua_State *L);

建立一張空表,並將其壓棧。 它等價於 lua_createtable(L, 0, 0) 。

lua_newthread

[-0, +1, e]

lua_State *lua_newthread (lua_State *L);

建立一條新線程,並將其壓棧, 並返回維護這個線程的 lua_State 指針。 這個函數返回的新線程共享原線程的全局環境, 可是它有獨立的運行棧。

沒有顯式的函數能夠用來關閉或銷燬掉一個線程。 線程跟其它 Lua 對象同樣是垃圾收集的條目之一。

lua_newuserdata

[-0, +1, e]

void *lua_newuserdata (lua_State *L, size_t size);

這個函數分配一塊指定大小的內存塊, 把內存塊地址做爲一個徹底用戶數據壓棧, 並返回這個地址。 宿主程序能夠隨意使用這塊內存。

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);
     }

在遍歷一張表的時候, 不要直接對鍵調用 lua_tolstring , 除非你知道這個鍵必定是一個字符串。 調用 lua_tolstring 有可能改變給定索引位置的值; 這會對下一次調用lua_next 形成影響。

關於迭代過程當中修改被迭代的表的注意事項參見 next 函數。

lua_Number

typedef double lua_Number;

Lua 中浮點數的類型。

Lua 中數字的類型。缺省是 double ,可是你能夠改爲 float 。 (參見 luaconf.h 中的 LUA_REAL 。)

lua_numbertointeger

int lua_numbertointeger (lua_Number n, lua_Integer *p);

將一個 Lua 浮點數轉換爲一個 Lua 整數。 這個宏假設 n 有對應的整數值。 若是該值在 Lua 整數可表示範圍內, 就將其轉換爲一個整數賦給 *p。 宏的結果是一個布爾量,表示轉換是否成功。 (注意、因爲圓整關係,這個範圍測試不用此宏很難作對。)

該宏有可能對其參數作屢次取值。

lua_pcall

[-(nargs + 1), +(nresults|1), –]

int lua_pcall (lua_State *L, int nargs, int nresults, int msgh);

以保護模式調用一個函數。

nargs 和 nresults 的含義與 lua_call 中的相同。 若是在調用過程當中沒有發生錯誤, lua_pcall 的行爲和 lua_call 徹底一致。 可是,若是有錯誤發生的話, lua_pcall 會捕獲它, 而後把惟一的值(錯誤消息)壓棧,而後返回錯誤碼。 同 lua_call 同樣, lua_pcall 老是把函數自己和它的參數從棧上移除。

若是 msgh 是 0 , 返回在棧頂的錯誤消息就和原始錯誤消息徹底一致。 不然, msgh 就被當成是 錯誤處理函數 在棧上的索引位置。 (在當前的實現裏,這個索引不能是僞索引。) 在發生運行時錯誤時, 這個函數會被調用而參數就是錯誤消息。 錯誤處理函數的返回值將被 lua_pcall 做爲錯誤消息返回在堆棧上。

典型的用法中,錯誤處理函數被用來給錯誤消息加上更多的調試信息, 好比棧跟蹤信息。 這些信息在 lua_pcall 返回後, 因爲棧已經展開,因此收集不到了。

lua_pcall 函數會返回下列常數 (定義在 lua.h 內)中的一個:

  • LUA_OK (0): 成功。
  • LUA_ERRRUN運行時錯誤。
  • LUA_ERRMEM內存分配錯誤。對於這種錯,Lua 不會調用錯誤處理函數。
  • LUA_ERRERR在運行錯誤處理函數時發生的錯誤。
  • LUA_ERRGCMM在運行 __gc 元方法時發生的錯誤。 (這個錯誤和被調用的函數無關。)

lua_pcallk

[-(nargs + 1), +(nresults|1), –]

int lua_pcallk (lua_State *L,
                int nargs,
                int nresults,
                int msgh,
                lua_KContext ctx,
                lua_KFunction k);

這個函數的行爲和 lua_pcall 徹底一致,只不過它還容許被調用的函數讓出 (參見 §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 閉包壓棧。

當建立了一個 C 函數後, 你能夠給它關聯一些值, 這就是在建立一個 C 閉包(參見 §4.4); 接下來不管函數什麼時候被調用,這些值均可以被這個函數訪問到。 爲了將一些值關聯到一個 C 函數上, 首先這些值須要先被壓入堆棧(若是有多個值,第一個先壓)。 接下來調用 lua_pushcclosure 來建立出閉包並把這個 C 函數壓到棧上。 參數 n 告之函數有多少個值須要關聯到函數上。 lua_pushcclosure 也會把這些值從棧上彈出。

n 的最大值是 255 。

當 n 爲零時, 這個函數將建立出一個 輕量 C 函數, 它就是一個指向 C 函數的指針。 這種狀況下,不可能拋出內存錯誤。

lua_pushcfunction

[-0, +1, –]

void lua_pushcfunction (lua_State *L, lua_CFunction f);

將一個 C 函數壓棧。 這個函數接收一個 C 函數指針, 並將一個類型爲 function 的 Lua 值壓棧。 當這個棧頂的值被調用時,將觸發對應的 C 函數。

註冊到 Lua 中的任何函數都必須遵循正確的協議來接收參數和返回值 (參見 lua_CFunction )。

lua_pushcfunction 是做爲一個宏定義出現的:

     #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 函數 sprintf 比較像, 不過有一些重要的區別:

  • 你不須要爲結果分配空間: 其結果是一個 Lua 字符串,由 Lua 來關心其內存分配 (同時經過垃圾收集來釋放內存)。
  • 這個轉換很是的受限。 不支持符號、寬度、精度。 轉換符只支持 '%%' (插入一個字符 '%'), '%s' (插入一個帶零終止符的字符串,沒有長度限制), '%f' (插入一個lua_Number), '%L' (插入一個 lua_Integer), '%p' (插入一個指針或是一個十六進制數), '%d' (插入一個 int), '%c' (插入一個用 int 表示的單字節字符),以及 '%U' (插入一個用 long int 表示的 UTF-8 字)。

lua_pushglobaltable

[-0, +1, –]

void lua_pushglobaltable (lua_State *L);

將全局環境壓棧。

lua_pushinteger

[-0, +1, –]

void lua_pushinteger (lua_State *L, lua_Integer n);

把值爲 n 的整數壓棧。

lua_pushlightuserdata

[-0, +1, –]

void lua_pushlightuserdata (lua_State *L, void *p);

把一個輕量用戶數據壓棧。

用戶數據是保留在 Lua 中的 C 值。 輕量用戶數據 表示一個指針 void*。 它是一個像數字同樣的值: 你不須要專門建立它,它也沒有獨立的元表,並且也不會被收集(由於歷來不須要建立)。 只要表示的 C 地址相同,兩個輕量用戶數據就相等。

lua_pushliteral

[-0, +1, e]

const char *lua_pushliteral (lua_State *L, const char *s);

這個宏等價於 lua_pushlstring, 區別僅在於只能在 s 是一個字面量時才能用它。 它會自動給出字符串的長度。

lua_pushlstring

[-0, +1, e]

const char *lua_pushlstring (lua_State *L, const char *s, size_t len);

把指針 s 指向的長度爲 len 的字符串壓棧。 Lua 對這個字符串作一個內部副本(或是複用一個副本), 所以 s 處的內存在函數返回後,能夠釋放掉或是馬上重用於其它用途。 字符串內能夠是任意二進制數據,包括零字符。

返回內部副本的指針。

lua_pushnil

[-0, +1, –]

void lua_pushnil (lua_State *L);

將空值壓棧。

lua_pushnumber

[-0, +1, –]

void lua_pushnumber (lua_State *L, lua_Number n);

把一個值爲 n 的浮點數壓棧。

lua_pushstring

[-0, +1, e]

const char *lua_pushstring (lua_State *L, const char *s);

將指針 s 指向的零結尾的字符串壓棧。 所以 s 處的內存在函數返回後,能夠釋放掉或是馬上重用於其它用途。

返回內部副本的指針。

若是 s 爲 NULL,將 nil 壓棧並返回 NULL

lua_pushthread

[-0, +1, –]

int lua_pushthread (lua_State *L);

把 L 表示的線程壓棧。 若是這個線程是當前狀態機的主線程的話,返回 1 。

lua_pushvalue

[-0, +1, –]

void lua_pushvalue (lua_State *L, int index);

把棧上給定索引處的元素做一個副本壓棧。

lua_pushvfstring

[-0, +1, e]

const char *lua_pushvfstring (lua_State *L,
                              const char *fmt,
                              va_list argp);

等價於 lua_pushfstring , 不過是用 va_list 接收參數,而不是用可變數量的實際參數。

lua_rawequal

[-0, +0, –]

int lua_rawequal (lua_State *L, int index1, int index2);

若是索引 index1 與索引 index2 處的值 自己相等(即不調用元方法),返回 1 。 不然返回 0 。 當任何一個索引無效時,也返回 0 。

lua_rawget

[-1, +1, –]

int lua_rawget (lua_State *L, int index);

相似於 lua_gettable , 可是做一次直接訪問(不觸發元方法)。

lua_rawgeti

[-0, +1, –]

int lua_rawgeti (lua_State *L, int index, lua_Integer n);

把 t[n] 的值壓棧, 這裏的 t 是指給定索引處的表。 這是一次直接訪問;就是說,它不會觸發元方法。

返回入棧值的類型。

lua_rawgetp

[-0, +1, –]

int lua_rawgetp (lua_State *L, int index, const void *p);

把 t[k] 的值壓棧, 這裏的 t 是指給定索引處的表, k 是指針 p 對應的輕量用戶數據。 這是一次直接訪問;就是說,它不會觸發元方法。

返回入棧值的類型。

lua_rawlen

[-0, +0, –]

size_t lua_rawlen (lua_State *L, int index);

返回給定索引處值的固有「長度」: 對於字符串,它指字符串的長度; 對於表;它指不觸發元方法的狀況下取長度操做('#')應獲得的值; 對於用戶數據,它指爲該用戶數據分配的內存塊的大小; 對於其它值,它爲 0 。

lua_rawset

[-2, +0, e]

void lua_rawset (lua_State *L, int index);

相似於 lua_settable , 可是是作一次直接賦值(不觸發元方法)。

lua_rawseti

[-1, +0, e]

void lua_rawseti (lua_State *L, int index, lua_Integer i);

等價於 t[i] = v , 這裏的 t 是指給定索引處的表, 而 v 是棧頂的值。

這個函數會將值彈出棧。 賦值是直接的;即不會觸發元方法。

lua_rawsetp

[-1, +0, e]

void lua_rawsetp (lua_State *L, int index, const void *p);

等價於 t[k] = v , 這裏的 t 是指給定索引處的表, k 是指針 p 對應的輕量用戶數據。 而 v 是棧頂的值。

這個函數會將值彈出棧。 賦值是直接的;即不會觸發元方法。

lua_Reader

typedef const char * (*lua_Reader) (lua_State *L,
                                    void *data,
                                    size_t *size);

lua_load 用到的讀取器函數, 每次它須要一塊新的代碼塊的時候, lua_load 就調用讀取器, 每次都會傳入一個參數 data 。 讀取器須要返回含有新的代碼塊的一塊內存的指針, 並把 size 設爲這塊內存的大小。 內存塊必須在下一次函數被調用以前一直存在。 讀取器能夠經過返回 NULL 或設 size 爲 0 來指示代碼塊結束。 讀取器可能返回多個塊,每一個塊能夠有任意的大於零的尺寸。

lua_register

[-0, +0, e]

void lua_register (lua_State *L, const char *name, lua_CFunction f);

把 C 函數 f 設到全局變量 name 中。 它經過一個宏定義:

     #define lua_register(L,n,f) \
            (lua_pushcfunction(L, f), lua_setglobal(L, n))

lua_remove

[-1, +0, –]

void lua_remove (lua_State *L, int index);

從給定有效索引處移除一個元素, 把這個索引之上的全部元素移下來填補上這個空隙。 不能用僞索引來調用這個函數,由於僞索引並不指向真實的棧上的位置。

lua_replace

[-1, +0, –]

void lua_replace (lua_State *L, int index);

把棧頂元素放置到給定位置而不移動其它元素 (所以覆蓋了那個位置處的值),而後將棧頂元素彈出。

lua_resume

[-?, +?, –]

int lua_resume (lua_State *L, lua_State *from, int nargs);

在給定線程中啓動或延續一條協程 。

要啓動一個協程的話, 你須要把主函數以及它須要的參數壓入線程棧; 而後調用 lua_resume , 把 nargs 設爲參數的個數。 此次調用會在協程掛起時或是結束運行後返回。 當函數返回時,堆棧中會有傳給 lua_yield 的全部值, 或是主函數的全部返回值。 當協程讓出, lua_resume 返回 LUA_YIELD , 若協程結束運行且沒有任何錯誤時,返回 0 。 若是有錯則返回錯誤代碼(參見 lua_pcall )。

在發生錯誤的狀況下, 堆棧沒有展開, 所以你能夠使用調試 API 來處理它。 錯誤消息放在棧頂在。

要延續一個協程, 你須要清除上次 lua_yield 遺留下的全部結果, 你把須要傳給 yield 做結果的值壓棧, 而後調用 lua_resume 。

參數 from 表示協程從哪一個協程中來延續 L 的。 若是不存在這樣一個協程,這個參數能夠是 NULL 。

lua_rotate

[-0, +0, –]

void lua_rotate (lua_State *L, int idx, int n);

把從 idx 開始到棧頂的元素輪轉 n 個位置。 對於 n 爲正數時,輪轉方向是向棧頂的; 當 n 爲負數時,向棧底方向輪轉 -n 個位置。 n 的絕對值不能夠比參於輪轉的切片長度大。

lua_setallocf

[-0, +0, –]

void lua_setallocf (lua_State *L, lua_Alloc f, void *ud);

把指定狀態機的分配器函數換成帶上用戶數據 ud 的 f 。

lua_setfield

[-1, +0, e]

void lua_setfield (lua_State *L, int index, const char *k);

作一個等價於 t[k] = v 的操做, 這裏 t 是給出的索引處的值, 而 v 是棧頂的那個值。

這個函數將把這個值彈出棧。 跟在 Lua 中同樣,這個函數可能觸發一個 "newindex" 事件的元方法 (參見 §2.4)。

lua_setglobal

[-1, +0, e]

void lua_setglobal (lua_State *L, const char *name);

從堆棧上彈出一個值,並將其設爲全局變量 name 的新值。

lua_seti

[-1, +0, e]

void lua_seti (lua_State *L, int index, lua_Integer n);

作一個等價於 t[n] = v 的操做, 這裏 t 是給出的索引處的值, 而 v 是棧頂的那個值。

這個函數將把這個值彈出棧。 跟在 Lua 中同樣,這個函數可能觸發一個 "newindex" 事件的元方法 (參見 §2.4)。

lua_setmetatable

[-1, +0, –]

void lua_setmetatable (lua_State *L, int index);

把一張表彈出棧,並將其設爲給定索引處的值的元表。

lua_settable

[-2, +0, e]

void lua_settable (lua_State *L, int index);

作一個等價於 t[k] = v 的操做, 這裏 t 是給出的索引處的值, v 是棧頂的那個值, k 是棧頂之下的值。

這個函數會將鍵和值都彈出棧。 跟在 Lua 中同樣,這個函數可能觸發一個 "newindex" 事件的元方法 (參見 §2.4)。

lua_settop

[-?, +?, –]

void lua_settop (lua_State *L, int index);

參數容許傳入任何索引以及 0 。 它將把堆棧的棧頂設爲這個索引。 若是新的棧頂比原來的大, 超出部分的新元素將被填爲 nil 。 若是 index 爲 0 , 把棧上全部元素移除。

lua_setuservalue

[-1, +0, –]

void lua_setuservalue (lua_State *L, int index);

從棧上彈出一個值並將其設爲給定索引處用戶數據的關聯值。

lua_State

typedef struct lua_State lua_State;

一個不透明的結構, 它指向一條線程並間接(經過該線程)引用了整個 Lua 解釋器的狀態。 Lua 庫是徹底可重入的: 它沒有任何全局變量。 狀態機全部的信息均可以經過這個結構訪問到。

這個結構的指針必須做爲第一個參數傳遞給每個庫函數。 lua_newstate 是一個例外, 這個函數會從頭建立一個 Lua 狀態機。

lua_status

[-0, +0, –]

int lua_status (lua_State *L);

返回線程 L 的狀態。

正常的線程狀態是 0 (LUA_OK)。 當線程用 lua_resume 執行完畢並拋出了一個錯誤時, 狀態值是錯誤碼。 若是線程被掛起,狀態爲 LUA_YIELD 。

你只能在狀態爲 LUA_OK 的線程中調用函數。 你能夠延續一個狀態爲 LUA_OK 的線程 (用於開始新協程)或是狀態爲 LUA_YIELD 的線程 (用於延續協程)。

lua_stringtonumber

[-0, +1, –]

size_t lua_stringtonumber (lua_State *L, const char *s);

將一個零結尾的字符串 s 轉換爲一個數字, 將這個數字壓棧,並返回字符串的總長度(即長度加一)。 轉換的結果多是整數也多是浮點數, 這取決於 Lua 的轉換語法(參見§3.1)。 這個字符串能夠有前置和後置的空格以及符號。 若是字符串並不是一個有效的數字,返回 0 並不把任何東西壓棧。 (注意,這個結果能夠當成一個布爾量使用,爲真即轉換成功。)

lua_toboolean

[-0, +0, –]

int lua_toboolean (lua_State *L, int index);

把給定索引處的 Lua 值轉換爲一個 C 中的布爾量( 0 或是 1 )。 和 Lua 中作的全部測試同樣, lua_toboolean 會把任何不一樣於 false 和 nil 的值看成真返回; 不然就返回假。 (若是你想只接收真正的 boolean 值, 就須要使用 lua_isboolean 來測試值的類型。)

lua_tocfunction

[-0, +0, –]

lua_CFunction lua_tocfunction (lua_State *L, int index);

把給定索引處的 Lua 值轉換爲一個 C 函數。 這個值必須是一個 C 函數; 若是不是就返回 NULL 。

lua_tointeger

[-0, +0, –]

lua_Integer lua_tointeger (lua_State *L, int index);

等價於調用 lua_tointegerx, 其參數 isnum 爲 NULL

lua_tointegerx

[-0, +0, –]

lua_Integer lua_tointegerx (lua_State *L, int index, int *isnum);

將給定索引處的 Lua 值轉換爲帶符號的整數類型 lua_Integer。 這個 Lua 值必須是一個整數,或是一個能夠被轉換爲整數 (參見 §3.4.3)的數字或字符串; 不然,lua_tointegerx 返回 0 。

若是 isnum 不是 NULL, *isnum 會被設爲操做是否成功。

lua_tolstring

[-0, +0, e]

const char *lua_tolstring (lua_State *L, int index, size_t *len);

把給定索引處的 Lua 值轉換爲一個 C 字符串。 若是 len 不爲 NULL , 它還把字符串長度設到 *len 中。 這個 Lua 值必須是一個字符串或是一個數字; 不然返回返回 NULL 。 若是值是一個數字, lua_tolstring 還會 把堆棧中的那個值的實際類型轉換爲一個字符串。 (當遍歷一張表的時候, 若把 lua_tolstring 做用在鍵上, 這個轉換有可能致使lua_next 弄錯。)

lua_tolstring 返回一個已對齊指針 指向 Lua 狀態機中的字符串。 這個字符串總能保證 ( C 要求的)最後一個字符爲零 ('\0') , 並且它容許在字符串內包含多個這樣的零。

由於 Lua 中可能發生垃圾收集, 因此不保證 lua_tolstring 返回的指針, 在對應的值從堆棧中移除後依然有效。

lua_tonumber

[-0, +0, –]

lua_Number lua_tonumber (lua_State *L, int index);

等價於調用 lua_tonumberx, 其參數 isnum 爲 NULL

lua_tonumberx

[-0, +0, –]

lua_Number lua_tonumberx (lua_State *L, int index, int *isnum);

把給定索引處的 Lua 值轉換爲 lua_Number 這樣一個 C 類型 (參見 lua_Number )。 這個 Lua 值必須是一個數字或是一個可轉換爲數字的字符串 (參見 §3.4.3); 不然,lua_tonumberx 返回 0 。

若是 isnum 不是 NULL, *isnum 會被設爲操做是否成功。

lua_topointer

[-0, +0, –]

const void *lua_topointer (lua_State *L, int index);

把給定索引處的值轉換爲通常的 C 指針 (void*) 。 這個值能夠是一個用戶對象,表 ,線程或是一個函數; 不然, lua_topointer 返回 NULL 。 不一樣的對象有不一樣的指針。 不存在把指針再轉回原有類型的方法。

這個函數一般只用於調試信息。

lua_tostring

[-0, +0, e]

const char *lua_tostring (lua_State *L, int index);

等價於調用 lua_tolstring , 其參數 len 爲 NULL 。

lua_tothread

[-0, +0, –]

lua_State *lua_tothread (lua_State *L, int index);

把給定索引處的值轉換爲一個 Lua 線程 (表示爲 lua_State*)。 這個值必須是一個線程; 不然函數返回 NULL

lua_touserdata

[-0, +0, –]

void *lua_touserdata (lua_State *L, int index);

若是給定索引處的值是一個徹底用戶數據, 函數返回其內存塊的地址。 若是值是一個輕量用戶數據, 那麼就返回它表示的指針。 不然,返回 NULL 。

lua_type

[-0, +0, –]

int lua_type (lua_State *L, int index);

返回給定有效索引處值的類型, 當索引無效(或沒法訪問)時則返回 LUA_TNONE。 lua_type 返回的類型被編碼爲一些個在 lua.h 中定義的常量: LUA_TNILLUA_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);

返回當前運行的函數(參見 §4.4)的第 i 個上值的僞索引。

lua_version

[-0, +0, v]

const lua_Number *lua_version (lua_State *L);

返回保存在 Lua 內核中儲存的版本數字的地址。 當調用時傳入一個合法的 lua_State , 返回建立該狀態機時的版本地址。 若是用 NULL 調用, 返回調用者的版本地址。

lua_Writer

typedef int (*lua_Writer) (lua_State *L,
                           const void* p,
                           size_t sz,
                           void* ud);

被 lua_dump 用到的寫入器函數。 每次 lua_dump 產生了一段新的代碼塊, 它都會調用寫入器。 傳入要寫入的緩衝區 (p) 和它的尺寸 (sz) , 以及傳給 lua_dump 的參數 data

寫入器會返回一個錯誤碼: 0 表示沒有錯誤; 別的值均表示一個錯誤, 而且會讓 lua_dump 中止再次調用寫入器。

lua_xmove

[-?, +?, –]

void lua_xmove (lua_State *from, lua_State *to, int n);

交換同一個狀態機下不一樣線程中的值。

這個函數會從 from 的棧上彈出 n 個值, 而後把它們壓入 to 的棧上。

lua_yield

[-?, +?, e]

int lua_yield (lua_State *L, int nresults);

這個函數等價於調用 lua_yieldk, 不一樣的是不提供延續函數(參見 §4.7)。 所以,當線程被延續,線程會繼續運行調用 lua_yield 函數的函數。

lua_yieldk

[-?, +?, e]

int lua_yieldk (lua_State *L,
                int nresults,
                lua_KContext ctx,
                lua_KFunction k);

讓出協程(線程)。

當 C 函數調用了 lua_yieldk, 當前運行的協程會掛起, 啓動這個線程的 lua_resume 調用返回。 參數 nresults 指棧上需返回給 lua_resume 的返回值的個數。

當協程再次被延續時, Lua 調用延續函數 k 繼續運行被掛起(參見 §4.7)的 C 函數。 延續函數會從前一個函數中接收到相同的棧, 棧中的 n 個返回值被移除而壓入了從lua_resume 傳入的參數。 此外,延續函數還會收到傳給 lua_yieldk 的參數 ctx

一般,這個函數不會返回; 當協程一次次延續,將從延續函數繼續運行。 然而,有一個例外: 當這個函數從一個逐行運行的鉤子函數(參見 §4.9) 中調用時,lua_yieldk 不能夠提供延續函數。 (也就是相似 lua_yield 的形式), 而此時,鉤子函數在調用完讓出後將馬上返回。 Lua 會使協程讓出,一旦協程再次被延續, 觸發鉤子的函數會繼續正常運行。

當一個線程處於未提供延續函數的 C 調用中,調用它會拋出一個錯誤。 從並不是用延續方式(例如:主線程)啓動的線程中調用它也會這樣。

4.9 – 調試接口

Lua 沒有內置的調試機制。 可是它提供了一組特殊的函數接口以及 鉤子。 這組接口可用於構建出不一樣的調試器、性能剖析器、 或是其它須要從解釋器獲取「內部信息」的工具。

lua_Debug

typedef struct lua_Debug {
  int event;
  const char *name;           /* (n) */
  const char *namewhat;       /* (n) */
  const char *what;           /* (S) */
  const char *source;         /* (S) */
  int currentline;            /* (l) */
  int linedefined;            /* (S) */
  int lastlinedefined;        /* (S) */
  unsigned char nups;         /* (u) 上值的數量 */
  unsigned char nparams;      /* (u) 參數的數量 */
  char isvararg;              /* (u) */
  char istailcall;            /* (t) */
  char short_src[LUA_IDSIZE]; /* (S) */
  /* 私有部分 */
  其它域
} lua_Debug;

這是一個攜帶有有關函數或活動記錄的各類信息的結構。 lua_getstack 只會填充結構的私有部分供後面使用。 調用 lua_getinfo 能夠在 lua_Debug 中填充那些可被使用的信息域。

下面對 lua_Debug 的各個域作一個說明:

  • source建立這個函數的代碼塊的名字。 若是 source 以 '@' 打頭, 指這個函數定義在一個文件中,而 '@' 以後的部分就是文件名。 若 source 以 '=' 打頭, 剩餘的部分由用戶行爲來決定如何表示源碼。 其它的狀況下,這個函數定義在一個字符串中, 而 source 正是那個字符串。
  • short_src一個「可打印版本」的 source ,用於出錯信息。
  • linedefined函數定義開始處的行號。
  • lastlinedefined函數定義結束處的行號。
  • what若是函數是一個 Lua 函數,則爲一個字符串 "Lua" ; 若是是一個 C 函數,則爲 "C"; 若是它是一個代碼塊的主體部分,則爲 "main"
  • currentline給定函數正在執行的那一行。 當提供不了行號信息的時候, currentline 被設爲 -1 。
  • name給定函數的一個合理的名字。 由於 Lua 中的函數是一等公民, 因此它們沒有固定的名字: 一些函數多是全局複合變量的值, 另外一些可能僅僅只是被保存在一張表的某個域中。 lua_getinfo 函數會檢查函數是怎樣被調用的, 以此來找到一個適合的名字。 若是它找不到名字, name 就被設置爲 NULL 。
  • namewhat用於解釋 name 域。 namewhat 的值能夠是 "global""local""method""field""upvalue", 或是 "" (空串)。 這取決於函數怎樣被調用。 (Lua 用空串表示其它選項都不符合。)
  • istailcall若是函數以尾調用形式調用,這個值就爲真。 在這種狀況下,當層的調用者不在棧中。
  • nups函數的上值個數。
  • nparams函數固定形參個數 (對於 C 函數永遠是 0 )。
  • isvararg若是函數是一個可變參數函數則爲真 (對於 C 函數永遠爲真)。

lua_gethook

[-0, +0, –]

lua_Hook lua_gethook (lua_State *L);

返回當前的鉤子函數。

lua_gethookcount

[-0, +0, –]

int lua_gethookcount (lua_State *L);

返回當前的鉤子計數。

lua_gethookmask

[-0, +0, –]

int lua_gethookmask (lua_State *L);

返回當前的鉤子掩碼。

lua_getinfo

[-(0|1), +(0|1|2), e]

int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);

返回一個指定的函數或函數調用的信息。

當用於取得一次函數調用的信息時, 參數 ar 必須是一個有效的活動的記錄。 這條記錄能夠是前一次調用 lua_getstack 獲得的, 或是一個鉤子 (參見 lua_Hook )獲得的參數。

用於獲取一個函數的信息時, 能夠把這個函數壓入堆棧, 而後把 what 字符串以字符 '>' 起頭。 (這會讓 lua_getinfo 從棧頂上彈出函數。) 例如,想知道函數 f 是在哪一行定義的, 你能夠使用下列代碼:

     lua_Debug ar;
     lua_getglobal(L, "f");  /* 取得全局變量 'f' */
     lua_getinfo(L, ">S", &ar);
     printf("%d\n", ar.linedefined);

what 字符串中的每一個字符都篩選出結構 ar 結構中一些域用於填充, 或是把一個值壓入堆棧:

  • 'n': 填充 name 及 namewhat 域;
  • 'S': 填充 source , short_src , linedefined , lastlinedefined ,以及 what 域;
  • 'l': 填充 currentline 域;
  • 't': 填充 istailcall 域;
  • 'u': 填充 nups, nparams,及 isvararg 域;
  • 'f': 把正在運行中指定層次處函數壓棧;
  • 'L': 將一張表壓棧,這張表中的整數索引用於描述函數中哪些行是有效行。 (有效行指有實際代碼的行,即你能夠置入斷點的行。 無效行包括空行和只有註釋的行。)

    若是這個選項和選項 'f' 同時使用, 這張表在函數以後壓棧。

這個函數出錯會返回 0 (例如,what 中有一個無效選項)。

lua_getlocal

[-0, +(0|1), –]

const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);

從給定活動記錄或從一個函數中獲取一個局部變量的信息。

對於第一種狀況, 參數 ar 必須是一個有效的活動的記錄。 這條記錄能夠是前一次調用 lua_getstack 獲得的, 或是一個鉤子 (參見 lua_Hook )的參數。 索引 n 用於選擇要檢閱哪一個局部變量; 參見 debug.getlocal 中關於變量的索引和名字的介紹。

lua_getlocal 將變量的值壓棧,並返回其名字。

對於第二種狀況,ar 必須填 NULL 。 須要探知的函數必須放在棧頂。 對於這種狀況,只有 Lua 函數的形參是可見的 (沒有關於還有哪些活動變量的信息) 也不會有任何值壓棧。

當索引大於活動的局部變量的數量, 返回 NULL (無任何壓棧)

lua_getstack

[-0, +0, –]

int lua_getstack (lua_State *L, int level, lua_Debug *ar);

獲取解釋器的運行時棧的信息。

這個函數用正在運行中的指定層次處函數的 活動記錄 來填寫 lua_Debug 結構的一部分。 0 層表示當前運行的函數, n+1 層的函數就是調用第 n 層 (尾調用例外,它不算在棧層次中) 函數的那一個。 若是沒有錯誤, lua_getstack 返回 1 ; 當調用傳入的層次大於堆棧深度的時候,返回 0 。

lua_getupvalue

[-0, +(0|1), –]

const char *lua_getupvalue (lua_State *L, int funcindex, int n);

獲取一個閉包的上值信息。 (對於 Lua 函數,上值是函數須要使用的外部局部變量, 所以這些變量被包含在閉包中。) lua_getupvalue 獲取第 n 個上值, 把這個上值的值壓棧, 而且返回它的名字。 funcindex 指向閉包在棧上的位置。 ( 由於上值在整個函數中都有效,因此它們沒有特別的次序。 所以,它們以字母次序來編號。)

當索引號比上值數量大的時候, 返回 NULL(並且不會壓入任何東西)。 對於 C 函數,全部上值的名字都是空串 ""

lua_Hook

typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);

用於調試的鉤子函數類型。

不管什麼時候鉤子被調用,它的參數 ar 中的 event 域都被設爲觸發鉤子的事件。 Lua 把這些事件定義爲如下常量: LUA_HOOKCALLLUA_HOOKRETLUA_HOOKTAILCALLLUA_HOOKLINE, LUA_HOOKCOUNT。 除此以外,對於 line 事件, currentline 域也被設置。 要想得到 ar 中的其餘域, 鉤子必須調用lua_getinfo 。

對於 call 事件,event 能夠是 LUA_HOOKCALL 這個一般值, 或是 LUA_HOOKTAILCALL 表示尾調用; 後一種狀況,沒有對應的返回事件。

當 Lua 運行在一個鉤子內部時, 它將屏蔽掉其它對鉤子的調用。 也就是說,若是一個鉤子函數內再調回 Lua 來執行一個函數或是一個代碼塊 , 這個執行操做不會觸發任何的鉤子。

鉤子函數不能有延續點, 即不能用一個非空的 k 調用 lua_yieldk, lua_pcallk,或 lua_callk

鉤子函數能夠在知足下列條件時讓出: 只有行計數事件可讓出,且不能在讓出時傳出任何值; 從鉤子裏讓出必須用 lua_yield 來結束鉤子的運行,且 nresults 必須爲零。

lua_sethook

[-0, +0, –]

void lua_sethook (lua_State *L, lua_Hook f, int mask, int count);

設置一個調試用鉤子函數。

參數 f 是鉤子函數。 mask 指定在哪些事件時會調用: 它由下列一組位常量構成 LUA_MASKCALL, LUA_MASKRET, LUA_MASKLINE, LUA_MASKCOUNT。 參數 count只在掩碼中包含有 LUA_MASKCOUNT 纔有意義。 對於每一個事件,鉤子被調用的狀況解釋以下:

  • call hook: 在解釋器調用一個函數時被調用。 鉤子將於 Lua 進入一個新函數後, 函數獲取參數前被調用。
  • return hook: 在解釋器從一個函數中返回時調用。 鉤子將於 Lua 離開函數以前的那一刻被調用。 沒有標準方法來訪問被函數返回的那些值。
  • line hook: 在解釋器準備開始執行新的一行代碼時, 或是跳轉到這行代碼中時(即便在同一行內跳轉)被調用。 (這個事件僅僅在 Lua 執行一個 Lua 函數時發生。)
  • count hook: 在解釋器每執行 count 條指令後被調用。 (這個事件僅僅在 Lua 執行一個 Lua 函數時發生。)

鉤子能夠經過設置 mask 爲零屏蔽。

lua_setlocal

[-(0|1), +0, –]

const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);

設置給定活動記錄中的局部變量的值。 參數 ar 與 n 和 lua_getlocal 中的同樣 (參見 lua_getlocal )。 lua_setlocal 把棧頂的值賦給變量而後返回變量的名字。 它會將值從棧頂彈出。

當索引大於活動局部變量的數量時,返回 NULL (什麼也不彈出)。

lua_setupvalue

[-(0|1), +0, –]

const char *lua_setupvalue (lua_State *L, int funcindex, int n);

設置閉包上值的值。 它把棧頂的值彈出並賦於上值並返回上值的名字。 參數 funcindex 與 n 和 lua_getupvalue 中的同樣 (參見 lua_getupvalue )。

當索引大於上值的數量時,返回 NULL (什麼也不彈出)。

lua_upvalueid

[-0, +0, –]

void *lua_upvalueid (lua_State *L, int funcindex, int n);

返回索引 funcindex 處的閉包中 編號爲 n 的上值的一個惟一標識符。 參數 funcindex 與 n 和 lua_getupvalue 中的同樣 (參見 lua_getupvalue )。 (但 n 不能夠大於上值的數量)。

這些惟一標識符可用於檢測不一樣的閉包是否共享了相同的上值。 共享同一個上值的 Lua 閉包(即它們指的同一個外部局部變量) 會針對這個上值返回相同的標識。

lua_upvaluejoin

[-0, +0, –]

void lua_upvaluejoin (lua_State *L, int funcindex1, int n1,
                                    int funcindex2, int n2);

讓索引 funcindex1 處的 Lua 閉包的第 n1 個上值 引用索引 funcindex2 處的 Lua 閉包的第 n2 個上值。

5 – 輔助庫

輔助庫 提供了一些便捷函數,方便在 C 中爲 Lua 編程。 基礎 API 提供了 C 和 Lua 交互用的主要函數, 而輔助庫則爲一些常見的任務提供了高階函數。

全部輔助庫中的函數和類型都定義在頭文件 lauxlib.h 中, 它們均帶有前綴 luaL_

輔助庫中的全部函數都基於基礎 API 實現。 故而它們並無提供任何基礎 API 實現不了的功能。 雖然如此,使用輔助庫可讓你的代碼更爲健壯。

一些輔助庫函數會在內部使用一些額外的棧空間。 當輔助庫使用的棧空間少於五個時, 它們不去檢查棧大小;而是簡單的假設棧夠用。

一些輔助庫中的函數用於檢查 C 函數的參數。 由於錯誤信息格式化爲指代參數 (例如,"bad argument #1"), 你就不要把這些函數用於參數以外的值了。

若是檢查沒法經過, luaL_check* 這些函數必定會拋出錯誤。

5.1 – 函數和類型

這裏咱們按字母表次序列出了輔助庫中的全部函數和類型。

luaL_addchar

[-?, +?, e]

void luaL_addchar (luaL_Buffer *B, char c);

向緩存 B (參見 luaL_Buffer ) 添加一個字節 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 ) 添加一個已在以前複製到緩衝區(參見 luaL_prepbuffer) 的長度爲 n 的字符串。

luaL_addstring

[-?, +?, e]

void luaL_addstring (luaL_Buffer *B, const char *s);

向緩存 B (參見 luaL_Buffer ) 添加一個零結尾的字符串 s

luaL_addvalue

[-1, +?, e]

void luaL_addvalue (luaL_Buffer *B);

向緩存 B (參見 luaL_Buffer ) 添加棧頂的一個值,隨後將其彈出。

這個函數是操做字符串緩存的函數中,惟一一個會(且必須)在棧上放置額外元素的。 這個元素將被加入緩存。

luaL_argcheck

[-0, +0, v]

void luaL_argcheck (lua_State *L,
                    int cond,
                    int arg,
                    const char *extramsg);

檢查 cond 是否爲真。 若是不爲真,以標準信息形式拋出一個錯誤 (參見 luaL_argerror)。

luaL_argerror

[-0, +0, v]

int luaL_argerror (lua_State *L, int arg, const char *extramsg);

拋出一個錯誤報告調用的 C 函數的第 arg 個參數的問題。 它使用下列標準信息幷包含了一段 extramsg 做爲註解:

     bad argument #arg to 'funcname' (extramsg)

這個函數永遠不會返回。

luaL_Buffer

typedef struct luaL_Buffer luaL_Buffer;

字符串緩存 的類型。

字符串緩存可讓 C 代碼分段構造一個 Lua 字符串。 使用模式以下:

  • 首先定義一個類型爲 luaL_Buffer 的變量 b
  • 調用 luaL_buffinit(L, &b) 初始化它。
  • 而後調用 luaL_add* 這組函數向其添加字符串片段。
  • 最後調用 luaL_pushresult(&b) 。 最後此次調用會在棧頂留下最終的字符串。

若是你預先知道結果串的長度, 你能夠這樣使用緩存:

  • 首先定義一個類型爲 luaL_Buffer 的變量 b
  • 而後調用 luaL_buffinitsize(L, &b, sz) 預分配 sz 大小的空間。
  • 接着將字符串複製入這個空間。
  • 最後調用 luaL_pushresultsize(&b, sz), 這裏的 sz 指已經複製到緩存內的字符串長度。

通常的操做過程當中,字符串緩存會使用不定量的棧槽。 所以,在使用緩存中,你不能假定目前棧頂在哪。 在對緩存操做的函數調用間,你均可以使用棧,只須要保證棧平衡便可; 即,在你作一次緩存操做調用時,當時的棧位置和上次調用緩存操做後的位置相同。 (對於 luaL_addvalue 是個惟一的例外。) 在調用完 luaL_pushresult 後, 棧會恢復到緩存初始化時的位置上,並在頂部壓入最終的字符串。

luaL_buffinit

[-0, +0, –]

void luaL_buffinit (lua_State *L, luaL_Buffer *B);

初始化緩存 B。 這個函數不會分配任何空間; 緩存必須以一個變量的形式聲明 (參見 luaL_Buffer)。

luaL_buffinitsize

[-?, +?, e]

char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz);

等價於調用序列 luaL_buffinit, luaL_prepbuffsize

luaL_callmeta

[-0, +(0|1), e]

int luaL_callmeta (lua_State *L, int obj, const char *e);

調用一個元方法。

若是在索引 obj 處的對象有元表, 且元表有域 e 。 這個函數會以該對象爲參數調用這個域。 這種狀況下,函數返回真並將調用返回值壓棧。 若是那個位置沒有元表,或沒有對應的元方法, 此函數返回假(並不會將任何東西壓棧)。

luaL_checkany

[-0, +0, v]

void luaL_checkany (lua_State *L, int arg);

檢查函數在 arg 位置是否有任何類型(包括 nil)的參數。

luaL_checkinteger

[-0, +0, v]

lua_Integer luaL_checkinteger (lua_State *L, int arg);

檢查函數的第 arg 個參數是不是一個 整數(或是能夠被轉換爲一個整數) 並以 lua_Integer 類型返回這個整數值。

luaL_checklstring

[-0, +0, v]

const char *luaL_checklstring (lua_State *L, int arg, size_t *l);

檢查函數的第 arg 個參數是不是一個 字符串,並返回該字符串; 若是 l 不爲 NULL , 將字符串的長度填入 *l

這個函數使用 lua_tolstring 來獲取結果。 因此該函數有可能引起的轉換都一樣有效。

luaL_checknumber

[-0, +0, v]

lua_Number luaL_checknumber (lua_State *L, int arg);

檢查函數的第 arg 個參數是不是一個 數字,並返回這個數字。

luaL_checkoption

[-0, +0, v]

int luaL_checkoption (lua_State *L,
                      int arg,
                      const char *def,
                      const char *const lst[]);

檢查函數的第 arg 個參數是不是一個 字符串,並在數組 lst (好比是零結尾的字符串數組) 中查找這個字符串。 返回匹配到的字符串在數組中的索引號。 若是參數不是字符串,或是字符串在數組中匹配不到,都將拋出錯誤。

若是 def 不爲 NULL, 函數就把 def 看成默認值。 默認值在參數 arg 不存在,或該參數是 nil 時生效。

這個函數一般用於將字符串映射爲 C 枚舉量。 (在 Lua 庫中作這個轉換可讓其使用字符串,而不是數字來作一些選項。)

luaL_checkstack

[-0, +0, v]

void luaL_checkstack (lua_State *L, int sz, const char *msg);

將棧空間擴展到 top + sz 個元素。 若是擴展不了,則拋出一個錯誤。 msg 是用於錯誤消息的額外文本 (NULL 表示不須要額外文本)。

luaL_checkstring

[-0, +0, v]

const char *luaL_checkstring (lua_State *L, int arg);

檢查函數的第 arg 個參數是不是一個 字符串並返回這個字符串。

這個函數使用 lua_tolstring 來獲取結果。 因此該函數有可能引起的轉換都一樣有效。

luaL_checktype

[-0, +0, v]

void luaL_checktype (lua_State *L, int arg, int t);

檢查函數的第 arg 個參數的類型是不是 t。 參見 lua_type 查閱類型 t 的編碼。

luaL_checkudata

[-0, +0, v]

void *luaL_checkudata (lua_State *L, int arg, const char *tname);

檢查函數的第 arg 個參數是不是一個類型爲 tname 的用戶數據 (參見 luaL_newmetatable )。 它會返回該用戶數據的地址 (參見 lua_touserdata)。

luaL_checkversion

[-0, +0, –]

void luaL_checkversion (lua_State *L);

檢查調用它的內核是不是建立這個 Lua 狀態機的內核。 以及調用它的代碼是否使用了相同的 Lua 版本。 同時也檢查調用它的內核與建立該 Lua 狀態機的內核 是否使用了同一片地址空間。

luaL_dofile

[-0, +?, e]

int luaL_dofile (lua_State *L, const char *filename);

加載並運行指定的文件。 它是用下列宏定義出來:

     (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))

若是沒有錯誤,函數返回假; 有錯則返回真。

luaL_dostring

[-0, +?, –]

int luaL_dostring (lua_State *L, const char *str);

加載並運行指定的字符串。 它是用下列宏定義出來:

     (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))

若是沒有錯誤,函數返回假; 有錯則返回真。

luaL_error

[-0, +0, v]

int luaL_error (lua_State *L, const char *fmt, ...);

拋出一個錯誤。 錯誤消息的格式由 fmt 給出。 後面需提供若干參數, 這些參數遵循 lua_pushfstring 中的規則。 若是能得到相關信息,它還會在消息前面加上錯誤發生時的文件名及行號。

這個函數永遠不會返回。 可是在 C 函數中一般遵循慣用法: return luaL_error(args) 。

luaL_execresult

[-0, +3, e]

int luaL_execresult (lua_State *L, int stat);

這個函數用於生成標準庫中和進程相關函數的返回值。 (指 os.execute 和 io.close)。

luaL_fileresult

[-0, +(1|3), e]

int luaL_fileresult (lua_State *L, int stat, const char *fname);

這個函數用於生成標準庫中和文件相關的函數的返回值。 (指 (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 域的值壓棧。 若是該對象沒有元表,或是該元表沒有相關域, 此函數什麼也不會壓棧並返回 LUA_TNIL

luaL_getmetatable

[-0, +1, –]

int luaL_getmetatable (lua_State *L, const char *tname);

將註冊表中 tname 對應的元表 (參見 luaL_newmetatable)壓棧。 若是沒有 tname 對應的元表,則將 nil 壓棧並返回假。

luaL_getsubtable

[-0, +1, e]

int luaL_getsubtable (lua_State *L, int idx, const char *fname);

確保 t[fname] 是一張表,並將這張表壓棧。 這裏的 t 指索引 idx 處的值。 若是它原來就是一張表,返回真; 不然爲它建立一張新表,返回假。

luaL_gsub

[-0, +1, e]

const char *luaL_gsub (lua_State *L,
                       const char *s,
                       const char *p,
                       const char *r);

將字符串 s 生成一個副本, 並將其中的全部字符串 p 都替換爲字符串 r 。 將結果串壓棧並返回它。

luaL_len

[-0, +0, e]

lua_Integer luaL_len (lua_State *L, int index);

以數字形式返回給定索引處值的「長度」; 它等價於在 Lua 中調用 '#' 的操做 (參見 §3.4.7)。 若是操做結果不是一個整數,則拋出一個錯誤。 (這種狀況只發生在觸發元方法時。)

luaL_loadbuffer

[-0, +1, –]

int luaL_loadbuffer (lua_State *L,
                     const char *buff,
                     size_t sz,
                     const char *name);

等價於 luaL_loadbufferx, 其 mode 參數等於 NULL

luaL_loadbufferx

[-0, +1, –]

int luaL_loadbufferx (lua_State *L,
                      const char *buff,
                      size_t sz,
                      const char *name,
                      const char *mode);

把一段緩存加載爲一個 Lua 代碼塊。 這個函數使用 lua_load 來加載 buff 指向的長度爲 sz 的內存區。

這個函數和 lua_load 返回值相同。 name 做爲代碼塊的名字,用於調試信息和錯誤消息。 mode 字符串的做用同函數 lua_load

luaL_loadfile

[-0, +1, e]

int luaL_loadfile (lua_State *L, const char *filename);

等價於 luaL_loadfilex, 其 mode 參數等於 NULL

luaL_loadfilex

[-0, +1, e]

int luaL_loadfilex (lua_State *L, const char *filename,
                                            const char *mode);

把一個文件加載爲 Lua 代碼塊。 這個函數使用 lua_load 加載文件中的數據。 代碼塊的名字被命名爲 filename。 若是 filename 爲 NULL, 它從標準輸入加載。 若是文件的第一行以 # 打頭,則忽略這一行。

mode 字符串的做用同函數 lua_load

此函數的返回值和 lua_load 相同, 不過它還可能產生一個叫作 LUA_ERRFILE 的出錯碼。這種錯誤發生於沒法打開或讀入文件時,或是文件的模式錯誤。

和 lua_load 同樣,這個函數僅加載代碼塊不運行。

luaL_loadstring

[-0, +1, –]

int luaL_loadstring (lua_State *L, const char *s);

將一個字符串加載爲 Lua 代碼塊。 這個函數使用 lua_load 加載一個零結尾的字符串 s

此函數的返回值和 lua_load 相同。

也和 lua_load 同樣,這個函數僅加載代碼塊不運行。

luaL_newlib

[-0, +1, e]

void luaL_newlib (lua_State *L, const luaL_Reg l[]);

建立一張新的表,並把列表 l 中的函數註冊進去。

它是用下列宏實現的:

     (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))

數組 l 必須是一個數組,而不能是一個指針。

luaL_newlibtable

[-0, +1, e]

void luaL_newlibtable (lua_State *L, const luaL_Reg l[]);

建立一張新的表,並預分配足夠保存下數組 l 內容的空間(但不填充)。 這是給 luaL_setfuncs 一塊兒用的 (參見 luaL_newlib)。

它以宏形式實現, 數組 l 必須是一個數組,而不能是一個指針。

luaL_newmetatable

[-0, +1, e]

int luaL_newmetatable (lua_State *L, const char *tname);

若是註冊表中已存在鍵 tname,返回 0 。 不然, 爲用戶數據的元表建立一張新表。 向這張表加入 __name = tname 鍵值對, 並將 [tname] = new table 添加到註冊表中, 返回 1 。 (__name項可用於一些錯誤輸出函數。)

這兩種狀況都會把最終的註冊表中關聯 tname 的值壓棧。

luaL_newstate

[-0, +0, –]

lua_State *luaL_newstate (void);

建立一個新的 Lua 狀態機。 它以一個基於標準 C 的 realloc 函數實現的內存分配器 調用 lua_newstate 。 並把可打印一些出錯信息到標準錯誤輸出的 panic 函數(參見 §4.6) 設置好,用於處理致命錯誤。

返回新的狀態機。 若是內存分配失敗,則返回 NULL 。

luaL_openlibs

[-0, +0, e]

void luaL_openlibs (lua_State *L);

打開指定狀態機中的全部 Lua 標準庫。

luaL_optinteger

[-0, +0, v]

lua_Integer luaL_optinteger (lua_State *L,
                             int arg,
                             lua_Integer d);

若是函數的第 arg 個參數是一個 整數(或能夠轉換爲一個整數), 返回該整數。 若該參數不存在或是 nil, 返回 d。 除此以外的狀況,拋出錯誤。

luaL_optlstring

[-0, +0, v]

const char *luaL_optlstring (lua_State *L,
                             int arg,
                             const char *d,
                             size_t *l);

若是函數的第 arg 個參數是一個 字符串,返回該字符串。 若該參數不存在或是 nil, 返回 d。 除此以外的狀況,拋出錯誤。

若 l 不爲 NULL, 將結果的長度填入 *l 。

luaL_optnumber

[-0, +0, v]

lua_Number luaL_optnumber (lua_State *L, int arg, lua_Number d);

若是函數的第 arg 個參數是一個 數字,返回該數字。 若該參數不存在或是 nil, 返回 d。 除此以外的狀況,拋出錯誤。

luaL_optstring

[-0, +0, v]

const char *luaL_optstring (lua_State *L,
                            int arg,
                            const char *d);

若是函數的第 arg 個參數是一個 字符串,返回該字符串。 若該參數不存在或是 nil, 返回 d。 除此以外的狀況,拋出錯誤。

luaL_prepbuffer

[-?, +?, e]

char *luaL_prepbuffer (luaL_Buffer *B);

等價於 luaL_prepbuffsize, 其預約義大小爲 LUAL_BUFFERSIZE

luaL_prepbuffsize

[-?, +?, e]

char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz);

返回一段大小爲 sz 的空間地址。 你能夠將字符串複製其中以加到緩存 B 內 (參見 luaL_Buffer)。 將字符串複製其中後,你必須調用 luaL_addsize 傳入字符串的大小,纔會真正把它加入緩存。

luaL_pushresult

[-?, +1, e]

void luaL_pushresult (luaL_Buffer *B);

結束對緩存 B 的使用,將最終的字符串留在棧頂。

luaL_pushresultsize

[-?, +1, e]

void luaL_pushresultsize (luaL_Buffer *B, size_t sz);

等價於 luaL_addsizeluaL_pushresult

luaL_ref

[-1, +0, e]

int luaL_ref (lua_State *L, int t);

針對棧頂的對象,建立並返回一個在索引 t 指向的表中的 引用 (最後會彈出棧頂對象)。

此引用是一個惟一的整數鍵。 只要你不向表 t 手工添加整數鍵, luaL_ref 能夠保證它返回的鍵的惟一性。 你能夠經過調用 lua_rawgeti(L, t, r) 來找回由 r 引用的對象。 函數luaL_unref 用來釋放一個引用關聯的對象

若是棧頂的對象是 nil, luaL_ref 將返回常量 LUA_REFNIL。 常量 LUA_NOREF 能夠保證和 luaL_ref 能返回的其它引用值不一樣。

luaL_Reg

typedef struct luaL_Reg {
  const char *name;
  lua_CFunction func;
} luaL_Reg;

用於 luaL_setfuncs 註冊函數的數組類型。 name 指函數名,func 是函數指針。 任何 luaL_Reg 數組必須以一對 name 與 func 皆爲 NULL 結束。

luaL_requiref

[-0, +1, e]

void luaL_requiref (lua_State *L, const char *modname,
                    lua_CFunction openf, int glb);

若是 modname 不在 package.loaded 中, 則調用函數 openf ,並傳入字符串 modname。 將其返回值置入 package.loaded[modname]。 這個行爲好似該函數經過require 調用過同樣。

若是 glb 爲真, 同時也講模塊設到全局變量 modname 裏。

在棧上留下該模塊的副本。

luaL_setfuncs

[-nup, +0, e]

void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);

把數組 l 中的全部函數 (參見 luaL_Reg) 註冊到棧頂的表中(該表在可選的上值之下,見下面的解說)。

若 nup 不爲零, 全部的函數都共享 nup 個上值。 這些值必須在調用以前,壓在表之上。 這些值在註冊完畢後都會從棧彈出。

luaL_setmetatable

[-0, +0, –]

void luaL_setmetatable (lua_State *L, const char *tname);

將註冊表中 tname 關聯元表 (參見 luaL_newmetatable) 設爲棧頂對象的元表。

luaL_Stream

typedef struct luaL_Stream {
  FILE *f;
  lua_CFunction closef;
} luaL_Stream;

標準輸入輸出庫中用到的標準文件句柄結構。

文件句柄實現爲一個徹底用戶數據, 其元表被稱爲 LUA_FILEHANDLE (LUA_FILEHANDLE 是一個表明真正元表的名字的宏)。 這張元表由標準輸入輸出庫(參見luaL_newmetatable)建立。

用戶數據必須以結構 luaL_Stream 開頭; 此結構其後能夠包含任何其它數據。 f 域指向一個 C 數據流 (若是它爲 NULL 表示一個沒有建立好的句柄)。 closef 域指向一個在關閉或回收該流時須要調用的 Lua 函數。 該函數將收到一個參數,即文件句柄。 它須要返回 true(操做成功)或 nil 加錯誤消息(出錯的時候)。 一旦 Lua 調用過這個域,該域的值就會修改成 NULL 以提示這個句柄已經被關閉了。

luaL_testudata

[-0, +0, e]

void *luaL_testudata (lua_State *L, int arg, const char *tname);

此函數和 luaL_checkudata 相似。 但它在測試失敗時會返回 NULL 而不是拋出錯誤。

luaL_tolstring

[-0, +1, e]

const char *luaL_tolstring (lua_State *L, int idx, size_t *len);

將給定索引處的 Lua 值轉換爲一個相應格式的 C 字符串。 結果串不只會壓棧,還會由函數返回。 若是 len 不爲 NULL , 它還把字符串長度設到 *len 中。

若是該值有一個帶 "__tostring" 域的元表, luaL_tolstring 會以該值爲參數去調用對應的元方法, 並將其返回值做爲結果。

luaL_traceback

[-0, +1, e]

void luaL_traceback (lua_State *L, lua_State *L1, const char *msg,
                     int level);

將棧 L1 的棧回溯信息壓棧。 若是 msg 不爲 NULL ,它會附加到棧回溯信息以前。 level 參數指明從第幾層開始作棧回溯。

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 層指當前正在運行的函數, 1 層指調用正在運行函數的函數, 依次類推。

這個函數用於構建錯誤消息的前綴。

6 – 標準庫

標準庫提供了一些有用的函數, 它們都是直接用 C API 實現的。 其中一些函數提供了本來語言就有的服務 (例如,type 與 getmetatable); 另外一些提供和「外部」打交道的服務(例如 I/O ); 還有些本能夠用 Lua 自己來實現,但在 C 中實現能夠知足關鍵點上的性能需求 (例如 table.sort)。

全部的庫都是直接用 C API 實現的,並以分離的 C 模塊形式提供。 目前,Lua 有下列標準庫:

除了基礎庫和包管理庫, 其它庫都把本身的函數放在一張全局表的域中, 或是以對象方法的形式提供。

要使用這些庫, C 的宿主程序須要先調用一下 luaL_openlibs 這個函數, 這樣就能打開全部的標準庫。 或者宿主程序也能夠用 luaL_requiref 分別打開這些庫:luaopen_base (基礎庫), luaopen_package (包管理庫), luaopen_coroutine (協程庫), luaopen_string (字符串庫), luaopen_utf8 (UTF8 庫),luaopen_table (表處理庫), luaopen_math (數學庫), luaopen_io (I/O 庫), luaopen_os (操做系統庫), luaopen_debug (調試庫)。 這些函數都定義在lualib.h 中。

6.1 – 基礎函數

基礎庫提供了 Lua 核心函數。 若是你不將這個庫包含在你的程序中, 你就須要當心檢查程序是否須要本身提供其中一些特性的實現。

 

assert (v [, message])

若是其參數 v 的值爲假(nil 或 false), 它就調用 error; 不然,返回全部的參數。 在錯誤狀況時, message 指那個錯誤對象; 若是不提供這個參數,參數默認爲 "assertion failed!" 。

 

collectgarbage ([opt [, arg]])

這個函數是垃圾收集器的通用接口。 經過參數 opt 它提供了一組不一樣的功能:

  • "collect": 作一次完整的垃圾收集循環。 這是默認選項。
  • "stop": 中止垃圾收集器的運行。 在調用重啓前,收集器只會因顯式的調用運行。
  • "restart": 重啓垃圾收集器的自動運行。
  • "count": 以 K 字節數爲單位返回 Lua 使用的總內存數。 這個值有小數部分,因此只須要乘上 1024 就能獲得 Lua 使用的準確字節數(除非溢出)。
  • "step": 單步運行垃圾收集器。 步長「大小」由 arg 控制。 傳入 0 時,收集器步進(不可分割的)一步。 傳入非 0 值, 收集器收集至關於 Lua 分配這些多(K 字節)內存的工做。 若是收集器結束一個循環將返回 true 。
  • "setpause": 將 arg 設爲收集器的 間歇率 (參見 §2.5)。 返回 間歇率 的前一個值。
  • "setstepmul": 將 arg 設爲收集器的 步進倍率 (參見 §2.5)。 返回 步進倍率 的前一個值。
  • "isrunning": 返回表示收集器是否在工做的布爾值 (即未被中止)。

 

dofile ([filename])

打開該名字的文件,並執行文件中的 Lua 代碼塊。 不帶參數調用時, dofile 執行標準輸入的內容(stdin)。 返回該代碼塊的全部返回值。 對於有錯誤的狀況,dofile 將錯誤反饋給調用者 (即,dofile 沒有運行在保護模式下)。

 

error (message [, level])

停止上一次保護函數調用, 將錯誤對象 message 返回。 函數 error 永遠不會返回。

當 message 是一個字符串時,一般 error 會把一些有關出錯位置的信息附加在消息的前頭。 level 參數指明瞭怎樣得到出錯位置。 對於 level 1 (默認值),出錯位置指 error函數調用的位置。 Level 2 將出錯位置指向調用 error的函數的函數;以此類推。 傳入 level 0 能夠避免在消息前添加出錯位置信息。

 

_G

一個全局變量(非函數), 內部儲存有全局環境(參見 §2.2)。 Lua 本身不使用這個變量; 改變這個變量的值不會對任何環境形成影響,反之亦然。

 

getmetatable (object)

若是 object 不包含元表,返回 nil 。 不然,若是在該對象的元表中有 "__metatable" 域時返回其關聯值, 沒有時返回該對象的元表。

 

ipairs (t)

返回三個值(迭代函數、表 t 以及 0 ), 如此,如下代碼

     for i,v in ipairs(t) do body end

將迭代鍵值對(1,t[1]) ,(2,t[2]), ... ,直到第一個空值。

 

load (chunk [, chunkname [, mode [, env]]])

加載一個代碼塊。

若是 chunk 是一個字符串,代碼塊指這個字符串。 若是 chunk 是一個函數, load 不斷地調用它獲取代碼塊的片段。 每次對 chunk 的調用都必須返回一個字符串牢牢鏈接在上次調用的返回串以後。 當返回空串、nil、或是不返回值時,都表示代碼塊結束。

若是沒有語法錯誤, 則以函數形式返回編譯好的代碼塊; 不然,返回 nil 加上錯誤消息。

若是結果函數有上值, env 被設爲第一個上值。 若不提供此參數,將全局環境替代它。 全部其它上值初始化爲 nil。 (當你加載主代碼塊時候,結果函數必定有且僅有一個上值_ENV (參見 §2.2))。 然而,若是你加載一個用函數(參見 string.dump, 結果函數能夠有任意數量的上值) 建立出來的二進制代碼塊時,全部的上值都是新建立出來的。 也就是說它們不會和別的任何函數共享。

chunkname 在錯誤消息和調試消息中(參見 §4.9),用於代碼塊的名字。 若是不提供此參數,它默認爲字符串chunk 。 chunk 不是字符串時,則爲 "=(load)" 。

字符串 mode 用於控制代碼塊是文本仍是二進制(即預編譯代碼塊)。 它能夠是字符串 "b" (只能是二進制代碼塊), "t" (只能是文本代碼塊), 或 "bt" (能夠是二進制也能夠是文本)。 默認值爲 "bt"。

Lua 不會對二進制代碼塊作健壯性檢查。 惡意構造一個二進制塊有可能把解釋器弄崩潰。

 

loadfile ([filename [, mode [, env]]])

和 load 相似, 不過是從文件 filename 或標準輸入(若是文件名未提供)中獲取代碼塊。

 

next (table [, index])

運行程序來遍歷表中的全部域。 第一個參數是要遍歷的表,第二個參數是表中的某個鍵。 next 返回該鍵的下一個鍵及其關聯的值。 若是用 nil 做爲第二個參數調用 next 將返回初始鍵及其關聯值。 當以最後一個鍵去調用,或是以 nil 調用一張空表時, next 返回 nil。 若是不提供第二個參數,將認爲它就是 nil。 特別指出,你能夠用 next(t) 來判斷一張表是不是空的。

索引在遍歷過程當中的次序無定義, 即便是數字索引也是這樣。 (若是想按數字次序遍歷表,能夠使用數字形式的 for 。)

當在遍歷過程當中你給表中並不存在的域賦值, next 的行爲是未定義的。 然而你能夠去修改那些已存在的域。 特別指出,你能夠清除一些已存在的域。

 

pairs (t)

若是 t 有元方法 __pairs, 以 t 爲參數調用它,並返回其返回的前三個值。

不然,返回三個值:next 函數, 表 t,以及 nil。 所以如下代碼

     for k,v in pairs(t) do body end

能迭表明 t 中的全部鍵值對。

參見函數 next 中關於迭代過程當中修改表的風險。

 

pcall (f [, arg1, ···])

傳入參數,以 保護模式 調用函數 f 。 這意味着 f 中的任何錯誤不會拋出; 取而代之的是,pcall 會將錯誤捕獲到,並返回一個狀態碼。 第一個返回值是狀態碼(一個布爾量), 當沒有錯誤時,其爲真。 此時,pcall 一樣會在狀態碼後返回全部調用的結果。 在有錯誤時,pcall 返回 false 加錯誤消息。

 

print (···)

接收任意數量的參數,並將它們的值打印到 stdout。 它用 tostring 函數將每一個參數都轉換爲字符串。 print 不用於作格式化輸出。僅做爲看一下某個值的快捷方式。 多用於調試。 完整的對輸出的控制,請使用 string.format 以及 io.write

 

rawequal (v1, v2)

在不觸發任何元方法的狀況下 檢查 v1 是否和 v2 相等。 返回一個布爾量。

 

rawget (table, index)

在不觸發任何元方法的狀況下 獲取 table[index] 的值。 table 必須是一張表; index 能夠是任何值。

 

rawlen (v)

在不觸發任何元方法的狀況下 返回對象 v 的長度。 v 能夠是表或字符串。 它返回一個整數。

 

rawset (table, index, value)

在不觸發任何元方法的狀況下 將 table[index] 設爲 value。 table 必須是一張表, index 能夠是 nil 與 NaN 以外的任何值。 value 能夠是任何 Lua 值。

這個函數返回 table

 

select (index, ···)

若是 index 是個數字, 那麼返回參數中第 index 個以後的部分; 負的數字會從後向前索引(-1 指最後一個參數)。 不然,index 必須是字符串 "#", 此時 select 返回參數的個數。

 

setmetatable (table, metatable)

給指定表設置元表。 (你不能在 Lua 中改變其它類型值的元表,那些只能在 C 裏作。) 若是 metatable 是 nil, 將指定表的元表移除。 若是原來那張元表有 "__metatable"域,拋出一個錯誤。

這個函數返回 table

 

tonumber (e [, base])

若是調用的時候沒有 base, tonumber 嘗試把參數轉換爲一個數字。 若是參數已是一個數字,或是一個能夠轉換爲數字的字符串, tonumber 就返回這個數字; 不然返回nil

字符串的轉換結果多是整數也多是浮點數, 這取決於 Lua 的轉換文法(參見 §3.1)。 (字符串能夠有前置和後置的空格,能夠帶符號。)

當傳入 base 調用它時, e 必須是一個以該進製表示的整數字符串。 進制能夠是 2 到 36 (包含 2 和 36)之間的任何整數。 大於 10 進制時,字母 'A' (大小寫都可)表示 10 , 'B' 表示 11,依次到 'Z' 表示 35 。 若是字符串 e 不是該進制下的合法數字, 函數返回 nil

 

tostring (v)

能夠接收任何類型,它將其轉換爲人可閱讀的字符串形式。 浮點數總被轉換爲浮點數的表現形式(小數點形式或是指數形式)。 (若是想徹底控制數字如何被轉換,能夠使用string.format。)

若是 v 有 "__tostring" 域的元表, tostring 會以 v 爲參數調用它。 並用它的結果做爲返回值。

 

type (v)

將參數的類型編碼爲一個字符串返回。 函數可能的返回值有 "nil" (一個字符串,而不是 nil 值), "number", "string", "boolean", "table", "function", "thread", "userdata"。

 

_VERSION

一個包含有當前解釋器版本號的全局變量(並不是函數)。 當前這個變量的值爲 "Lua 5.3"。

 

xpcall (f, msgh [, arg1, ···])

這個函數和 pcall 相似。 不過它能夠額外設置一個消息處理器 msgh

6.2 – 協程管理

關於協程的操做做爲基礎庫的一個子庫, 被放在一個獨立表 coroutine 中。 協程的介紹參見 §2.6 。

 

coroutine.create (f)

建立一個主體函數爲 f 的新協程。 f 必須是一個 Lua 的函數。 返回這個新協程,它是一個類型爲 "thread" 的對象。

 

coroutine.isyieldable ()

若是正在運行的協程可讓出,則返回真。

不在主線程中或不在一個沒法讓出的 C 函數中時,當前協程是可以讓出的。

 

coroutine.resume (co [, val1, ···])

開始或繼續協程 co 的運行。 當你第一次延續一個協程,它會從主體函數處開始運行。 val1, ... 這些值會以參數形式傳入主體函數。 若是該協程被讓出,resume 會從新啓動它;val1, ... 這些參數會做爲讓出點的返回值。

若是協程運行起來沒有錯誤, resume 返回 true 加上傳給 yield 的全部值 (當協程讓出), 或是主體函數的全部返回值(當協程停止)。 若是有任何錯誤發生, resume 返回false 加錯誤消息。

 

coroutine.running ()

返回當前正在運行的協程加一個布爾量。 若是當前運行的協程是主線程,其爲真。

 

coroutine.status (co)

以字符串形式返回協程 co 的狀態: 當協程正在運行(它就是調用 status 的那個) ,返回 "running"; 若是協程調用 yield 掛起或是尚未開始運行,返回 "suspended"; 若是協程是活動的,都並不在運行(即它正在延續其它協程),返回 "normal"; 若是協程運行完主體函數或因錯誤中止,返回 "dead"

 

coroutine.wrap (f)

建立一個主體函數爲 f 的新協程。 f 必須是一個 Lua 的函數。 返回一個函數, 每次調用該函數都會延續該協程。 傳給這個函數的參數都會做爲 resume 的額外參數。 和resume 返回相同的值, 只是沒有第一個布爾量。 若是發生任何錯誤,拋出這個錯誤。

 

coroutine.yield (···)

掛起正在調用的協程的執行。 傳遞給 yield 的參數都會轉爲 resume 的額外返回值。

6.3 – 模塊

包管理庫提供了從 Lua 中加載模塊的基礎庫。 只有一個導出函數直接放在全局環境中: require。 全部其它的部分都導出在表 package 中。

 

require (modname)

加載一個模塊。 這個函數首先查找 package.loaded 表, 檢測 modname 是否被加載過。 若是被加載過,require 返回 package.loaded[modname] 中保存的值。 不然,它試着爲模塊尋找 加載器 。

require 遵循 package.searchers 序列的指引來查找加載器。 若是改變這個序列,咱們能夠改變 require 如何查找一個模塊。 下列說明基於 package.searchers 的默認配置。

首先 require 查找 package.preload[modname] 。 若是這裏有一個值,這個值(必須是一個函數)就是那個加載器。 不然 require 使用 Lua 加載器去查找 package.path 的路徑。 若是查找失敗,接着使用 C 加載器去查找 package.cpath 的路徑。 若是都失敗了,再嘗試 一體化 加載器 (參見 package.searchers)。

每次找到一個加載器,require 都用兩個參數調用加載器: modname 和一個在獲取加載器過程當中獲得的參數。 (若是經過查找文件獲得的加載器,這個額外參數是文件名。) 若是加載器返回非空值, require 將這個值賦給 package.loaded[modname]。 若是加載器沒能返回一個非空值用於賦給 package.loaded[modname], require 會在那裏設入 true 。 不管是什麼狀況,require 都會返回 package.loaded[modname] 的最終值。

若是在加載或運行模塊時有錯誤, 或是沒法爲模塊找到加載器, require 都會拋出錯誤。

 

package.config

一個描述有一些爲包管理準備的編譯期配置信息的串。 這個字符串由一系列行構成:

  • 第一行是目錄分割串。 對於 Windows 默認是 '\' ,對於其它系統是 '/' 。
  • 第二行是用於路徑中的分割符。默認值是 ';' 。
  • 第三行是用於標記模板替換點的字符串。 默認是 '?' 。
  • 第四行是在 Windows 中將被替換成執行程序所在目錄的路徑的字符串。 默認是 '!' 。
  • 第五行是一個記號,該記號以後的全部文本將在構建 luaopen_ 函數名時被忽略掉。 默認是 '-'。

 

package.cpath

這個路徑被 require 在 C 加載器中作搜索時用到。

Lua 用和初始化 Lua 路徑 package.path 相同的方式初始化 C 路徑 package.cpath 。 它會使用環境變量 LUA_CPATH_5_3 或 環境變量 LUA_CPATH 初始化。 要麼就採用luaconf.h 中定義的默認路徑。

 

package.loaded

用於 require 控制哪些模塊已經被加載的表。 當你請求一個 modname 模塊,且 package.loaded[modname] 不爲假時, require 簡單返回儲存在內的值。

這個變量僅僅是對真正那張表的引用; 改變這個值並不會改變 require 使用的表。

 

package.loadlib (libname, funcname)

讓宿主程序動態連接 C 庫 libname 。

當 funcname 爲 "*", 它僅僅鏈接該庫,讓庫中的符號都導出給其它動態連接庫使用。 不然,它查找庫中的函數 funcname ,以 C 函數的形式返回這個函數。 所以,funcname 必須遵循原型 lua_CFunction (參見 lua_CFunction)。

這是一個低階函數。 它徹底繞過了包模塊系統。 和 require 不一樣, 它不會作任何路徑查詢,也不會自動加擴展名。 libname 必須是一個 C 庫須要的完整的文件名,若是有必要,須要提供路徑和擴展名。 funcname 必須是 C 庫須要的準確名字 (這取決於使用的 C 編譯器和連接器)。

這個函數在標準 C 中不支持。 所以,它只在部分平臺有效 ( Windows ,Linux ,Mac OS X, Solaris, BSD, 加上支持 dlfcn 標準的 Unix 系統)。

 

package.path

這個路徑被 require 在 Lua 加載器中作搜索時用到。

在啓動時,Lua 用環境變量 LUA_PATH_5_3 或環境變量 LUA_PATH 來初始化這個變量。 或採用 luaconf.h 中的默認路徑。 環境變量中出現的全部 ";;" 都會被替換成默認路徑。

 

package.preload

保存有一些特殊模塊的加載器 (參見 require)。

這個變量僅僅是對真正那張表的引用; 改變這個值並不會改變 require 使用的表。

 

package.searchers

用於 require 控制如何加載模塊的表。

這張表內的每一項都是一個 查找器函數。 當查找一個模塊時, require 按次序調用這些查找器, 並傳入模塊名(require 的參數)做爲惟一的一個參數。 此函數能夠返回另外一個函數(模塊的 加載器)加上另外一個將傳遞給這個加載器的參數。 或是返回一個描述爲什麼沒有找到這個模塊的字符串 (或是返回 nil 什麼也不想說)。

Lua 用四個查找器函數初始化這張表。

第一個查找器就是簡單的在 package.preload 表中查找加載器。

第二個查找器用於查找 Lua 庫的加載庫。 它使用儲存在 package.path 中的路徑來作查找工做。 查找過程和函數 package.searchpath 描述的一致。

第三個查找器用於查找 C 庫的加載庫。 它使用儲存在 package.cpath 中的路徑來作查找工做。 一樣, 查找過程和函數 package.searchpath 描述的一致。 例如,若是 C 路徑是這樣一個字符串

     "./?.so;./?.dll;/usr/local/?/init.so"

查找器查找模塊 foo 會依次嘗試打開文件 ./foo.so./foo.dll, 以及 /usr/local/foo/init.so。 一旦它找到一個 C 庫, 查找器首先使用動態連接機制鏈接該庫。 而後嘗試在該庫中找到能夠用做加載器的 C 函數。 這個 C 函數的名字是 "luaopen_" 緊接模塊名的字符串, 其中字符串中全部的下劃線都會被替換成點。 此外,若是模塊名中有橫線, 橫線後面的部分(包括橫線)都被去掉。 例如,若是模塊名爲 a.b.c-v2.1, 函數名就是 luaopen_a_b_c

第四個搜索器是 一體化加載器。 它從 C 路徑中查找指定模塊的根名字。 例如,當請求 a.b.c 時, 它將查找 a 這個 C 庫。 若是找獲得,它會在裏面找子模塊的加載函數。 在咱們的例子中,就是找 luaopen_a_b_c。 利用這個機制,能夠把若干 C 子模塊打包進單個庫。 每一個子模塊均可以有本來的加載函數名。

除了第一個(預加載)搜索器外,每一個搜索器都會返回 它找到的模塊的文件名。 這和 package.searchpath 的返回值同樣。 第一個搜索器沒有返回值。

 

package.searchpath (name, path [, sep [, rep]])

在指定 path 中搜索指定的 name 。

路徑是一個包含有一系列以分號分割的 模板 構成的字符串。 對於每一個模板,都會用 name 替換其中的每一個問號(若是有的話)。 且將其中的 sep (默認是點)替換爲 rep (默認是系統的目錄分割符)。 而後嘗試打開這個文件名。

例如,若是路徑是字符串

     "./?.lua;./?.lc;/usr/local/?/init.lua"

搜索 foo.a 這個名字將 依次嘗試打開文件 ./foo/a.lua , ./foo/a.lc ,以及 /usr/local/foo/a/init.lua

返回第一個能夠用讀模式打開(並立刻關閉該文件)的文件的名字。 若是不存在這樣的文件,返回 nil 加上錯誤消息。 (這條錯誤消息列出了全部嘗試打開的文件名。)

6.4 – 字符串處理

這個庫提供了字符串處理的通用函數。 例如字符串查找、子串、模式匹配等。 當在 Lua 中對字符串作索引時,第一個字符從 1 開始計算(而不是 C 裏的 0 )。 索引能夠是負數,它指從字符串末尾反向解析。 即,最後一個字符在 -1 位置處,等等。

字符串庫中的全部函數都在表 string 中。 它還將其設置爲字符串元表的 __index 域。 所以,你能夠以面向對象的形式使用字符串函數。 例如,string.byte(s,i) 能夠寫成s:byte(i)

字符串庫假定採用單字節字符編碼。

 

string.byte (s [, i [, j]])

返回字符 s[i], s[i+1], ... ,s[j] 的內部數字編碼。 i 的默認值是 1 ; j 的默認值是 i。 這些索引以函數 string.sub 的規則修正。

數字編碼沒有必要跨平臺。

 

string.char (···)

接收零或更多的整數。 返回和參數數量相同長度的字符串。 其中每一個字符的內部編碼值等於對應的參數值。

數字編碼沒有必要跨平臺。

 

string.dump (function [, strip])

返回包含有以二進制方式表示的(一個 二進制代碼塊 )指定函數的字符串。 以後能夠用 load 調用這個字符串得到 該函數的副本(可是綁定新的上值)。 若是 strip 爲真值, 二進制代碼塊不攜帶該函數的調試信息 (局部變量名,行號,等等。)。

帶上值的函數只保存上值的數目。 當(再次)加載時,這些上值被更新爲 nil 的實例。 (你能夠使用調試庫按你須要的方式來序列化上值,並重載到函數中)

 

string.find (s, pattern [, init [, plain]])

查找第一個字符串 s 中匹配到的 pattern (參見 §6.4.1)。 若是找到一個匹配,find 會返回 s 中關於它起始及終點位置的索引; 不然,返回 nil。 第三個可選數字參數 init 指明從哪裏開始搜索; 默認值爲 1 ,同時能夠是負值。 第四個可選參數 plain 爲 true 時, 關閉模式匹配機制。 此時函數僅作直接的 「查找子串」的操做, 而 pattern 中沒有字符被看做魔法字符。 注意,若是給定了 plain ,就必須寫上 init 。

若是在模式中定義了捕獲,捕獲到的若干值也會在兩個索引以後返回。

 

string.format (formatstring, ···)

返回不定數量參數的格式化版本, 格式化串爲第一個參數(必須是一個字符串)。 格式化字符串遵循 ISO C 函數 sprintf 的規則。 不一樣點在於選項 *hLlnp 不支持, 另外還增長了一個選項 q。 q 選項將一個字符串格式化爲兩個雙引號括起,對內部字符作恰當的轉義處理的字符串。 該字符串能夠安全的被 Lua 解釋器讀回來。 例如,調用

     string.format('%q', 'a string with "quotes" and \n new line')

會產生字符串:

     "a string with \"quotes\" and \
      new line"

選項 A and a (若是有的話), EefG, and g 都期待一個對應的數字參數。 選項 cdiouX, and x 則期待一個整數。 選項 q 期待一個字符串; 選項 s 期待一個沒有內嵌零的字符串。 若是選項 s 對應的參數不是字符串,它會用和 tostring 一致的規則轉換成字符串。

 

string.gmatch (s, pattern)

返回一個迭代器函數。 每次調用這個函數都會繼續以 pattern (參見 §6.4.1) 對 s 作匹配,並返回全部捕獲到的值。 若是 pattern 中沒有指定捕獲,則每次捕獲整個pattern

下面這個例子會循環迭代字符串 s 中全部的單詞, 並逐行打印:

     s = "hello world from Lua"
     for w in string.gmatch(s, "%a+") do
       print(w)
     end

下一個例子從指定的字符串中收集全部的鍵值對 key=value 置入一張表:

     t = {}
     s = "from=world, to=Lua"
     for k, v in string.gmatch(s, "(%w+)=(%w+)") do
       t[k] = v
     end

對這個函數來講,模板前開始的 '^' 不會當成錨點。由於這樣會阻止迭代。

 

string.gsub (s, pattern, repl [, n])

將字符串 s 中,全部的(或是在 n 給出時的前 n 個) pattern (參見 §6.4.1)都替換成 repl ,並返回其副本。 repl 能夠是字符串、表、或函數。 gsub 還會在第二個返回值返回一共發生了多少次匹配。 gsub 這個名字來源於 Global SUBstitution 。

若是 repl 是一個字符串,那麼把這個字符串做爲替換品。 字符 % 是一個轉義符: repl 中的全部形式爲 %d 的串表示 第 d 個捕獲到的子串,d 能夠是 1 到 9 。 串 %0 表示整個匹配。 串 %% 表示單個 %

若是 repl 是張表,每次匹配時都會用第一個捕獲物做爲鍵去查這張表。

若是 repl 是個函數,則在每次匹配發生時都會調用這個函數。 全部捕獲到的子串依次做爲參數傳入。

任何狀況下,模板中沒有設定捕獲都當作是捕獲整個模板。

若是表的查詢結果或函數的返回結果是一個字符串或是個數字, 都將其做爲替換用串; 而在返回 false 或 nil 時不做替換 (即保留匹配前的原始串)。

這裏有一些用例:

     x = string.gsub("hello world", "(%w+)", "%1 %1")
     --> x="hello hello world world"
     
     x = string.gsub("hello world", "%w+", "%0 %0", 1)
     --> x="hello hello world"
     
     x = string.gsub("hello world from Lua", "(%w+)%s*(%w+)", "%2 %1")
     --> x="world hello Lua from"
     
     x = string.gsub("home = $HOME, user = $USER", "%$(%w+)", os.getenv)
     --> x="home = /home/roberto, user = roberto"
     
     x = string.gsub("4+5 = $return 4+5$", "%$(.-)%$", function (s)
           return load(s)()
         end)
     --> x="4+5 = 9"
     
     local t = {name="lua", version="5.3"}
     x = string.gsub("$name-$version.tar.gz", "%$(%w+)", t)
     --> x="lua-5.3.tar.gz"

 

string.len (s)

接收一個字符串,返回其長度。 空串 "" 的長度爲 0 。 內嵌零也統計在內,所以 "a\000bc\000" 的長度爲 5 。

 

string.lower (s)

接收一個字符串,將其中的大寫字符都轉爲小寫後返回其副本。 其它的字符串不會更改。 對大寫字符的定義取決於當前的區域設置。

 

string.match (s, pattern [, init])

在字符串 s 中找到第一個能用 pattern (參見 §6.4.1)匹配到的部分。 若是能找到,match 返回其中的捕獲物; 不然返回 nil 。 若是 pattern 中未指定捕獲, 返回整個pattern 捕獲到的串。 第三個可選數字參數 init 指明從哪裏開始搜索; 它默認爲 1 且能夠是負數。

 

string.pack (fmt, v1, v2, ···)

返回一個打包了(即以二進制形式序列化) v1v2 等值的二進制字符串。 字符串 fmt 爲打包格式(參見 §6.4.2)。

 

string.packsize (fmt)

返回以指定格式用 string.pack 打包的字符串的長度。 格式化字符串中不能夠有變長選項 's' 或 'z' (參見 §6.4.2)。

 

string.rep (s, n [, sep])

返回 n 個字符串 s 以字符串 sep 爲分割符連在一塊兒的字符串。 默認的 sep 值爲空字符串(即沒有分割符)。 若是 n 不是正數則返回空串。

 

string.reverse (s)

返回字符串 s 的翻轉串。

 

string.sub (s, i [, j])

返回 s 的子串, 該子串從 i 開始到 j 爲止; i 和 j 均可覺得負數。 若是不給出 j ,就當它是 -1 (和字符串長度相同)。 特別是, 調用 string.sub(s,1,j) 能夠返回 s 的長度爲 j的前綴串, 而 string.sub(s, -i) 返回長度爲 i 的後綴串。

若是在對負數索引轉義後 i 小於 1 的話,就修正回 1 。 若是 j 比字符串的長度還大,就修正爲字符串長度。 若是在修正以後,i 大於 j, 函數返回空串。

 

string.unpack (fmt, s [, pos])

返回以格式 fmt (參見 §6.4.2) 打包在字符串 s (參見 string.pack) 中的值。 選項 pos(默認爲 1 )標記了從 s 中哪裏開始讀起。 讀完全部的值後,函數返回 s 中第一個未讀字節的位置。

 

string.upper (s)

接收一個字符串,將其中的小寫字符都轉爲大寫後返回其副本。 其它的字符串不會更改。 對小寫字符的定義取決於當前的區域設置。

6.4.1 – 匹配模式

Lua 中的匹配模式直接用常規的字符串來描述。 它用於模式匹配函數 string.findstring.gmatchstring.gsubstring.match。 這一節表述了這些字符串的語法及含義(即它能匹配到什麼)。

字符類:

字符類 用於表示一個字符集合。 下列組合可用於字符類:

  • x(這裏 x 不能是 魔法字符 ^$()%.[]*+-? 中的一員) 表示字符 x 自身。
  • .(一個點)可表示任何字符。
  • %a表示任何字母。
  • %c表示任何控制字符。
  • %d表示任何數字。
  • %g表示任何除空白符外的可打印字符。
  • %l表示全部小寫字母。
  • %p表示全部標點符號。
  • %s表示全部空白字符。
  • %u表示全部大寫字母。
  • %w表示全部字母及數字。
  • %x表示全部 16 進制數字符號。
  • %x(這裏的 x 是任意非字母或數字的字符) 表示字符 x。 這是對魔法字符轉義的標準方法。 全部非字母或數字的字符 (包括全部標點,也包括非魔法字符) 均可以用前置一個 '%' 放在模式串中表示自身。
  • [set]表示 set 中全部字符的聯合。 能夠以 '-' 鏈接,升序書寫範圍兩端的字符來表示一個範圍的字符集。 上面提到的 %x 形式也能夠在 set 中使用 表示其中的一個元素。 其它出如今 set 中的字符則表明它們本身。 例如,[%w_] (或 [_%w]) 表示全部的字母數字加下劃線), [0-7] 表示 8 進制數字, [0-7%l%-] 表示 8 進制數字加小寫字母與 '-' 字符。

    交叉使用類和範圍的行爲未定義。 所以,像 [%a-z] 或 [a-%%] 這樣的模式串沒有意義。

  • [^set]表示 set 的補集, 其中 set 如上面的解釋。

全部單個字母表示的類別(%a%c,等), 若將其字母改成大寫,均表示對應的補集。 例如,%S 表示全部非空格的字符。

如何定義字母、空格、或是其餘字符組取決於當前的區域設置。 特別注意:[a-z] 未必等價於 %l 。

模式條目:

模式條目 能夠是

  • 單個字符類匹配該類別中任意單個字符;
  • 單個字符類跟一個 '*', 將匹配零或多個該類的字符。 這個條目老是匹配儘量長的串;
  • 單個字符類跟一個 '+', 將匹配一或更多個該類的字符。 這個條目老是匹配儘量長的串;
  • 單個字符類跟一個 '-', 將匹配零或更多個該類的字符。 和 '*' 不一樣, 這個條目老是匹配儘量短的串;
  • 單個字符類跟一個 '?', 將匹配零或一個該類的字符。 只要有可能,它會匹配一個;
  • %n, 這裏的 n 能夠從 1 到 9; 這個條目匹配一個等於 n 號捕獲物(後面有描述)的子串。
  • %bxy, 這裏的 x 和 y 是兩個明確的字符; 這個條目匹配以 x 開始 y 結束, 且其中 x 和 y 保持 平衡 的字符串。 意思是,若是從左到右讀這個字符串,對每次讀到一個 x就 +1 ,讀到一個 y 就 -1, 最終結束處的那個 y 是第一個記數到 0 的 y。 舉個例子,條目 %b() 能夠匹配到括號平衡的表達式。
  • %f[set], 指 邊境模式; 這個條目會匹配到一個位於 set 內某個字符以前的一個空串, 且這個位置的前一個字符不屬於 set 。 集合 set 的含義如前面所述。 匹配出的那個空串之開始和結束點的計算就當作該處有個字符 '\0' 同樣。

模式:

模式 指一個模式條目的序列。 在模式最前面加上符號 '^' 將錨定從字符串的開始處作匹配。 在模式最後面加上符號 '$' 將使匹配過程錨定到字符串的結尾。 若是 '^' 和 '$' 出如今其它位置,它們均沒有特殊含義,只表示自身。

捕獲:

模式能夠在內部用小括號括起一個子模式; 這些子模式被稱爲 捕獲物。 當匹配成功時,由 捕獲物 匹配到的字符串中的子串被保存起來用於將來的用途。 捕獲物以它們左括號的次序來編號。 例如,對於模式 "(a*(.)%w(%s*))" , 字符串中匹配到 "a*(.)%w(%s*)" 的部分保存在第一個捕獲物中 (所以是編號 1 ); 由 "." 匹配到的字符是 2 號捕獲物, 匹配到 "%s*" 的那部分是 3 號。

做爲一個特例,空的捕獲 () 將捕獲到當前字符串的位置(它是一個數字)。 例如,若是將模式 "()aa()" 做用到字符串 "flaaap" 上,將產生兩個捕獲物: 3 和 5 。

6.4.2 – 打包和解包用到的格式串

用於 string.pack, string.packsize, string.unpack 的第一個參數。 它是一個描述了須要建立或讀取的結構之佈局。

格式串是由轉換選項構成的序列。 這些轉換選項列在後面:

  • <設爲小端編碼
  • >設爲大端編碼
  • =大小端遵循本地設置
  • ![n]將最大對齊數設爲 n (默認遵循本地對齊設置)
  • b一個有符號字節 (char)
  • B一個無符號字節 (char)
  • h一個有符號 short (本地大小)
  • H一個無符號 short (本地大小)
  • l一個有符號 long (本地大小)
  • L一個無符號 long (本地大小)
  • j一個 lua_Integer
  • J一個 lua_Unsigned
  • T一個 size_t (本地大小)
  • i[n]一個 n 字節長(默認爲本地大小)的有符號 int
  • I[n]一個 n 字節長(默認爲本地大小)的無符號 int
  • f一個 float (本地大小)
  • d一個 double (本地大小)
  • n一個 lua_Number
  • cnn字節固定長度的字符串
  • z零結尾的字符串
  • s[n]長度加內容的字符串,其長度編碼爲一個 n 字節(默認是個 size_t) 長的無符號整數。
  • x一個字節的填充
  • Xop按選項 op 的方式對齊(忽略它的其它方面)的一個空條目
  • ' ': (空格)忽略

( "[n]" 表示一個可選的整數。) 除填充、空格、配置項(選項 "xX <=>!")外, 每一個選項都關聯一個參數(對於 string.pack) 或結果(對於 string.unpack)。

對於選項 "!n", "sn", "in", "In", n 能夠是 1 到 16 間的整數。 全部的整數選項都將作溢出檢查; string.pack 檢查提供的值是否能用指定的字長表示; string.unpack 檢查讀出的值可否置入 Lua 整數中。

任何格式串都假設有一個 "!1=" 前綴, 即最大對齊爲 1 (無對齊)且採用本地大小端設置。

對齊行爲按以下規則工做: 對每一個選項,格式化時都會填充一些字節直到數據從一個特定偏移處開始, 這個位置是該選項的大小和最大對齊數中較小的那個數的倍數; 這個較小值必須是 2 個整數次方。 選項 "c" 及 "z" 不作對齊處理; 選項 "s" 對對齊遵循其開頭的整數。

string.pack 用零去填充 (string.unpack 則忽略它)。

6.5 – UTF-8 支持

這個庫提供了對 UTF-8 編碼的基礎支持。 全部的函數都放在表 utf8 中。 此庫不提供除編碼處理以外的任何 Unicode 支持。 全部須要瞭解字符含義的操做,好比字符分類,都不在此範疇。

除非另有說明, 當一個函數須要一個字節位置的參數時, 都假定這個位置要麼從字節序列的開始計算, 要麼從字符串長度加一的位置算。 和字符串庫同樣,負的索引從字符串末尾計起。

 

utf8.char (···)

接收零或多個整數, 將每一個整數轉換成對應的 UTF-8 字節序列,並返回這些序列鏈接到一塊兒的字符串。

 

utf8.charpattern

用於精確匹配到一個 UTF-8 字節序列的模式(是一個字符串,並不是函數)"[\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 是位置(按字節數)而 c 是每一個字符的編號。 若是處理到一個不合法的字節序列,將拋出一個錯誤。

 

utf8.codepoint (s [, i [, j]])

一整數形式返回 s 中 從位置 i 到 j 間(包括兩端) 全部字符的編號。 默認的 i 爲 1 ,默認的 j 爲 i。 若是碰上不合法的字節序列,拋出一個錯誤。

 

utf8.len (s [, i [, j]])

返回字符串 s 中 從位置 i 到 j 間 (包括兩端) UTF-8 字符的個數。 默認的 i 爲 1 ,默認的 j 爲 -1 。 若是它找到任何不合法的字節序列, 返回假值加上第一個不合法字節的位置。

 

utf8.offset (s, n [, i])

返回編碼在 s 中的第 n 個字符的開始位置(按字節數) (從位置 i 處開始統計)。 負 n 則取在位置 i 前的字符。 當 n 是非負數時,默認的 i 是 1, 不然默認爲 #s + 1。 所以,utf8.offset(s, -n) 取字符串的倒數第 n 個字符的位置。 若是指定的字符不在其中或在結束點以後,函數返回 nil

做爲特例,當 n 等於 0 時, 此函數返回含有 s 第 i 字節的那個字符的開始位置。

這個函數假定 s 是一個合法的 UTF-8 字符串。

6.6 – 表處理

這個庫提供了表處理的通用函數。 全部函數都放在表 table 中。

記住,不管什麼時候,若一個操做須要取表的長度, 這張表必須是一個真序列,或是擁有 __len 元方法 (參見 §3.4.7 )。 全部的函數都忽略傳入參數的那張表中的非數字鍵。

 

table.concat (list [, sep [, i [, j]]])

提供一個列表,其全部元素都是字符串或數字,返回字符串 list[i]..sep..list[i+1] ··· sep..list[j]。 sep 的默認值是空串, i 的默認值是 1 , j 的默認值是 #list 。 若是 i 比 j大,返回空串。

 

table.insert (list, [pos,] value)

在 list 的位置 pos 處插入元素 value , 並後移元素 list[pos], list[pos+1], ···, list[#list] 。 pos 的默認值爲 #list+1 , 所以調用 table.insert(t,x) 會將 x 插在列表 t 的末尾。

 

table.move (a1, f, e, t [,a2])

將元素從表 a1 移到表 a2。 這個函數作了次等價於後面這個多重賦值的等價操做: a2[t],··· = a1[f],···,a1[e]。 a2 的默認值爲 a1。 目標區間能夠和源區間重疊。 索引 f 必須是正數。

 

table.pack (···)

返回用全部參數以鍵 1,2, 等填充的新表, 並將 "n" 這個域設爲參數的總數。 注意這張返回的表不必定是一個序列。

 

table.remove (list [, pos])

移除 list 中 pos 位置上的元素,並返回這個被移除的值。 當 pos 是在 1 到 #list 之間的整數時, 它向前移動元素 list[pos+1], list[pos+2], ···, list[#list] 並刪除元素list[#list]; 索引 pos 能夠是 #list + 1 ,或在 #list 爲 0 時能夠是 0 ; 在這些狀況下,函數刪除元素 list[pos]

pos 默認爲 #list, 所以調用 table.remove(l) 將移除表 l 的最後一個元素。

 

table.sort (list [, comp])

在表內從 list[1] 到 list[#list] 原地 對其間元素按指定次序排序。 若是提供了 comp , 它必須是一個能夠接收兩個列表內元素爲參數的函數。 當第一個元素須要排在第二個元素以前時,返回真 (所以 not comp(list[i+1],list[i]) 在排序結束後將爲真)。 若是沒有提供 comp, 將使用標準 Lua 操做 < 做爲替代品。

排序算法並不穩定; 即當兩個元素次序相等時,它們在排序後的相對位置可能會改變。

 

table.unpack (list [, i [, j]])

返回列表中的元素。 這個函數等價於

     return list[i], list[i+1], ···, list[j]

i 默認爲 1 ,j 默認爲 #list

6.7 – 數學函數

這個庫提供了基本的數學函數。 因此函數都放在表 math 中。 註解有 "integer/float" 的函數會對整數參數返回整數結果, 對浮點(或混合)參數返回浮點結果。 圓整函數(math.ceilmath.floormath.modf) 在結果在整數範圍內時返回整數,不然返回浮點數。

 

math.abs (x)

返回 x 的絕對值。(integer/float)

 

math.acos (x)

返回 x 的反餘弦值(用弧度表示)。

 

math.asin (x)

返回 x 的反正弦值(用弧度表示)。

 

math.atan (y [, x])

返回 y/x 的反正切值(用弧度表示)。 它會使用兩個參數的符號來找到結果落在哪一個象限中。 (即便 x 爲零時,也能夠正確的處理。)

默認的 x 是 1 , 所以調用 math.atan(y) 將返回 y 的反正切值。

 

math.ceil (x)

返回不小於 x 的最小整數值。

 

math.cos (x)

返回 x 的餘弦(假定參數是弧度)。

 

math.deg (x)

將角 x 從弧度轉換爲角度。

 

math.exp (x)

返回 ex 的值 (e 爲天然對數的底)。

 

math.floor (x)

返回不大於 x 的最大整數值。

 

math.fmod (x, y)

返回 x 除以 y,將商向零圓整後的餘數。 (integer/float)

 

math.huge

浮點數 HUGE_VAL, 這個數比任何數字值都大。

 

math.log (x [, base])

返回以指定底的 x 的對數。 默認的 base 是 e (所以此函數返回 x 的天然對數)。

 

math.max (x, ···)

返回參數中最大的值, 大小由 Lua 操做 < 決定。 (integer/float)

 

math.maxinteger

最大值的整數。

 

math.min (x, ···)

返回參數中最小的值, 大小由 Lua 操做 < 決定。 (integer/float)

 

math.mininteger

最小值的整數。

 

math.modf (x)

返回 x 的整數部分和小數部分。 第二個結果必定是浮點數。

 

math.pi

π 的值。

 

math.rad (x)

將角 x 從角度轉換爲弧度。

 

math.random ([m [, n]])

當不帶參數調用時, 返回一個 [0,1) 區間內一致分佈的浮點僞隨機數。 當以兩個整數 m 與 n 調用時, math.random 返回一個 [m, n] 區間 內一致分佈的整數僞隨機數。 (值m-n 不能是負數,且必須在 Lua 整數的表示範圍內。) 調用 math.random(n) 等價於 math.random(1,n)

這個函數是對 C 提供的位隨機數函數的封裝。 對其統計屬性不做擔保。

 

math.randomseed (x)

把 x 設爲僞隨機數發生器的「種子」: 相同的種子產生相同的隨機數列。

 

math.sin (x)

返回 x 的正弦值(假定參數是弧度)。

 

math.sqrt (x)

返回 x 的平方根。 (你也能夠使用乘方 x^0.5 來計算這個值。)

 

math.tan (x)

返回 x 的正切值(假定參數是弧度)。

 

math.tointeger (x)

若是 x 能夠轉換爲一個整數, 返回該整數。 不然返回 nil

 

math.type (x)

若是 x 是整數,返回 "integer", 若是它是浮點數,返回 "float", 若是 x 不是數字,返回 nil

 

math.ult (m, n)

若是整數 m 和 n 以無符號整數形式比較, m 在 n 之下,返回布爾真不然返回假。

6.8 – 輸入輸出庫

I/O 庫提供了兩套不一樣風格的文件處理接口。 第一種風格使用隱式的文件句柄; 它提供設置默認輸入文件及默認輸出文件的操做, 全部的輸入輸出操做都針對這些默認文件。 第二種風格使用顯式的文件句柄。

當使用隱式文件句柄時, 全部的操做都由表 io 提供。 若使用顯式文件句柄, io.open 會返回一個文件句柄,且全部的操做都由該文件句柄的方法來提供。

表 io 中也提供了三個 和 C 中含義相同的預約義文件句柄: io.stdin, io.stdout, 以及 io.stderr。 I/O 庫永遠不會關閉這些文件。

除非另有說明, I/O 函數在出錯時都返回 nil (第二個返回值爲錯誤消息,第三個返回值爲系統相關的錯誤碼)。 成功時返回與 nil 不一樣的值。 在非 POSIX 系統上, 根據錯誤碼取出錯誤消息的過程可能並不是線程安全的, 由於這使用了 C 的全局變量 errno 。

 

io.close ([file])

等價於 file:close()。 不給出 file 時將關閉默認輸出文件。

 

io.flush ()

等價於 io.output():flush()

 

io.input ([file])

用文件名調用它時,(以文本模式)來打開該名字的文件, 並將文件句柄設爲默認輸入文件。 若是用文件句柄去調用它, 就簡單的將該句柄設爲默認輸入文件。 若是調用時不傳參數,它返回當前的默認輸入文件。

在出錯的狀況下,函數拋出錯誤而不是返回錯誤碼。

 

io.lines ([filename ···])

以讀模式打開指定的文件名並返回一個迭代函數。 此迭代函數的工做方式和用一個已打開的文件去調用 file:lines(···) 獲得的迭代器相同。 當迭代函數檢測到文件結束, 它不返回值(讓循環結束)並自動關閉文件。

調用 io.lines() (不傳文件名) 等價於 io.input():lines("*l"); 即,它將按行迭代標準輸入文件。 在此狀況下,循環結束後它不會關閉文件。

在出錯的狀況下,函數拋出錯誤而不是返回錯誤碼。

 

io.open (filename [, mode])

這個函數用字符串 mode 指定的模式打開一個文件。 返回新的文件句柄。 當出錯時,返回 nil 加錯誤消息。

mode 字符串能夠是下列任意值:

  • "r": 讀模式(默認);
  • "w": 寫模式;
  • "a": 追加模式;
  • "r+": 更新模式,全部以前的數據都保留;
  • "w+": 更新模式,全部以前的數據都刪除;
  • "a+": 追加更新模式,全部以前的數據都保留,只容許在文件尾部作寫入。

mode 字符串能夠在最後加一個 'b' , 這會在某些系統上以二進制方式打開文件。

 

io.output ([file])

相似於 io.input。 不過都針對默認輸出文件操做。

 

io.popen (prog [, mode])

這個函數和系統有關,不是全部的平臺都提供。

用一個分離進程開啓程序 prog, 返回的文件句柄可用於從這個程序中讀取數據 (若是 mode 爲 "r",這是默認值) 或是向這個程序寫入輸入(當 mode 爲 "w" 時)。

 

io.read (···)

等價於 io.input():read(···)

 

io.tmpfile ()

返回一個臨時文件的句柄。 這個文件以更新模式打開,在程序結束時會自動刪除。

 

io.type (obj)

檢查 obj 是不是合法的文件句柄。 若是 obj 它是一個打開的文件句柄,返回字符串 "file"。 若是 obj 是一個關閉的文件句柄,返回字符串 "closed file"。 若是 obj 不是文件句柄,返回 nil 。

 

io.write (···)

等價於 io.output():write(···)

 

file:close ()

關閉 file。 注意,文件在句柄被垃圾回收時會自動關閉, 可是多久之後發生,時間不可預期的。

當關閉用 io.popen 建立出來的文件句柄時, file:close 返回 os.execute 會返回的同樣的值。

 

file:flush ()

將寫入的數據保存到 file 中。

 

file:lines (···)

返回一個迭代器函數, 每次調用迭代器時,都從文件中按指定格式讀數據。 若是沒有指定格式,使用默認值 "l" 。 看一個例子

     for c in file:lines(1) do body end

會從文件當前位置開始,中不斷讀出字符。 和 io.lines 不一樣, 這個函數在循環結束後不會關閉文件。

在出錯的狀況下,函數拋出錯誤而不是返回錯誤碼。

 

file:read (···)

讀文件 file, 指定的格式決定了要讀什麼。 對於每種格式,函數返回讀出的字符對應的字符串或數字。 若不能以該格式對應讀出數據則返回 nil。 (對於最後這種狀況, 函數不會讀出後續的格式。) 當調用時不傳格式,它會使用默認格式讀下一行(見下面描述)。

提供的格式有

  • "n": 讀取一個數字,根據 Lua 的轉換文法,可能返回浮點數或整數。 (數字能夠有前置或後置的空格,以及符號。) 只要能構成合法的數字,這個格式老是去讀儘可能長的串; 若是讀出來的前綴沒法構成合法的數字 (好比空串,"0x" 或 "3.4e-"), 就停止函數運行,返回 nil
  • "i": 讀取一個整數,返回整數值。
  • "a": 從當前位置開始讀取整個文件。 若是已在文件末尾,返回空串。
  • "l": 讀取一行並忽略行結束標記。 當在文件末尾時,返回 nil 這是默認格式。
  • "L": 讀取一行並保留行結束標記(若是有的話), 當在文件末尾時,返回 nil
  • number讀取一個不超過這個數量字節數的字符串。 當在文件末尾時,返回 nil。 若是 number 爲零, 它什麼也不讀,返回一個空串。 當在文件末尾時,返回 nil

格式 "l" 和 "L" 只能用於文本文件。

 

file:seek ([whence [, offset]])

設置及獲取基於文件開頭處計算出的位置。 設置的位置由 offset 和 whence 字符串 whence 指定的基點決定。基點能夠是:

  • "set": 基點爲 0 (文件開頭);
  • "cur": 基點爲當前位置了;
  • "end": 基點爲文件尾;

當 seek 成功時,返回最終從文件開頭計算起的文件的位置。 當 seek 失敗時,返回 nil 加上一個錯誤描述字符串。

whence 的默認值是 "cur", offset 默認爲 0 。 所以,調用 file:seek() 能夠返回文件當前位置,並不改變它; 調用 file:seek("set") 將位置設爲文件開頭(並返回 0); 調用file:seek("end") 將位置設到文件末尾,並返回文件大小。

 

file:setvbuf (mode [, size])

設置輸出文件的緩衝模式。 有三種模式:

  • "no": 不緩衝;輸出操做馬上生效。
  • "full": 徹底緩衝;只有在緩存滿或當你顯式的對文件調用 flush(參見 io.flush) 時才真正作輸出操做。
  • "line": 行緩衝; 輸出將到每次換行前, 對於某些特殊文件(例如終端設備)緩衝到任何輸入前。

對於後兩種狀況,size 以字節數爲單位 指定緩衝區大小。 默認會有一個恰當的大小。

 

file:write (···)

將參數的值逐個寫入 file。 參數必須是字符串或數字。

成功時,函數返回 file。 不然返回 nil 加錯誤描述字符串。

6.9 – 操做系統庫

這個庫都經過表 os 實現。

 

os.clock ()

返回程序使用的按秒計 CPU 時間的近似值。

 

os.date ([format [, time]])

返回一個包含日期及時刻的字符串或表。 格式化方法取決於所給字符串 format

若是提供了 time 參數, 格式化這個時間 (這個值的含義參見 os.time 函數)。 不然,date 格式化當前時間。

若是 format 以 '!' 打頭, 日期以協調世界時格式化。 在這個可選字符項以後, 若是 format 爲字符串 "*t", date 返回有後續域的表: year (四位數字),month (1–12),day (1–31), hour (0–23),min (0–59),sec (0–61), wday (星期幾,星期天爲 1 ), yday (當年的第幾天), 以及 isdst (夏令時標記,一個布爾量)。 對於最後一個域,若是該信息不提供的話就不存在。

若是 format 並不是 "*t", date 以字符串形式返回, 格式化方法遵循 ISO C 函數 strftime 的規則。

若是不傳參數調用, date 返回一個合理的日期時間串, 格式取決於宿主程序以及當前的區域設置 (即,os.date() 等價於 os.date("%c"))。

在非 POSIX 系統上, 因爲這個函數依賴 C 函數 gmtime 和 localtime, 它可能並不是線程安全的。

 

os.difftime (t2, t1)

返回以秒計算的時刻 t1 到 t2 的差值。 (這裏的時刻是由 os.time 返回的值)。 在 POSIX,Windows,和其它一些系統中,這個值就等於 t2-t1

 

os.execute ([command])

這個函數等價於 ISO C 函數 system。 它調用系統解釋器執行 command。 若是命令成功運行完畢,第一個返回值就是 true, 不然是 nil otherwise。 在第一個返回值以後,函數返回一個字符串加一個數字。以下:

  • "exit": 命令正常結束; 接下來的數字是命令的退出狀態碼。
  • "signal": 命令被信號打斷; 接下來的數字是打斷該命令的信號。

若是不帶參數調用, os.execute 在系統解釋器存在的時候返回真。

 

os.exit ([code [, close]])

調用 ISO C 函數 exit 終止宿主程序。 若是 code 爲 true, 返回的狀態碼是 EXIT_SUCCESS; 若是 code 爲 false, 返回的狀態碼是 EXIT_FAILURE; 若是 code 是一個數字, 返回的狀態碼就是這個數字。 code 的默認值爲 true

若是第二個可選參數 close 爲真, 在退出前關閉 Lua 狀態機。

 

os.getenv (varname)

返回進程環境變量 varname 的值, 若是該變量未定義,返回 nil 。

 

os.remove (filename)

刪除指定名字的文件(在 POSIX 系統上能夠是一個空目錄) 若是函數失敗,返回 nil 加一個錯誤描述串及出錯碼。

 

os.rename (oldname, newname)

將名字爲 oldname 的文件或目錄改名爲 newname。 若是函數失敗,返回 nil 加一個錯誤描述串及出錯碼。

 

os.setlocale (locale [, category])

設置程序的當前區域。 locale 是一個區域設置的系統相關字符串; category 是一個描述有改變哪一個分類的可選字符串: "all""collate", "ctype", "monetary""numeric", 或 "time"; 默認的分類爲 "all"。 此函數返回新區域的名字。 若是請求未被獲准,返回 nil 。

當 locale 是一個空串, 當前區域被設置爲一個在實現中定義好的本地區域。 當 locale 爲字符串 "C", 當前區域被設置爲標準 C 區域。

當第一個參數爲 nil 時, 此函數僅返回當前區域指定分類的名字。

因爲這個函數依賴 C 函數 setlocale, 它可能並不是線程安全的。

 

os.time ([table])

當不傳參數時,返回當前時刻。 若是傳入一張表,就返回由這張表表示的時刻。 這張表必須包含域 yearmonth,及 day; 能夠包含有 hour (默認爲 12 ), min (默認爲 0), sec (默認爲 0),以及 isdst (默認爲 nil)。 關於這些域的詳細描述,參見 os.date 函數。

返回值是一個含義由你的系統決定的數字。 在 POSIX,Windows,和其它一些系統中, 這個數字統計了從指定時間("epoch")開始經歷的秒數。 對於另外的系統,其含義未定義, 你只能把 time 的返回數字用於 os.date 和 os.difftime 的參數。

 

os.tmpname ()

返回一個可用於臨時文件的文件名字符串。 這個文件在使用前必須顯式打開,再也不使用時須要顯式刪除。

在 POSIX 系統上, 這個函數會以此文件名建立一個文件以迴避安全風險。 (別人可能未經容許在獲取到這個文件名到建立該文件之間的時刻建立此文件。) 你依舊須要在使用它的時候先打開,並最後刪除(即便你沒使用到)。

只有有可能,你更應該使用 io.tmpfile, 由於該文件能夠在程序結束時自動刪除。

6.10 – 調試庫

這個庫提供了 Lua 程序調試接口(§4.9)的功能。 其中一些函數違反了 Lua 代碼的基本假定 (例如,不會從函數以外訪問函數的局部變量; 用戶數據的元表不會被 Lua 代碼修改; Lua 程序不會崩潰), 所以它們有可能危害到其它代碼的安全性。 此外,庫裏的一些函數可能運行的很慢。

這個庫裏的全部函數都提供在表 debug 內。 全部操做線程的函數,可選的第一個參數都是針對的線程。 默認值永遠是當前線程。

 

debug.debug ()

進入一個用戶交互模式,運行用戶輸入的每一個字符串。 使用簡單的命令以及其它調試設置,用戶能夠檢閱全局變量和局部變量, 改變變量的值,計算一些表達式,等等。 輸入一行僅包含 cont 的字符串將結束這個函數, 這樣調用者就能夠繼續向下運行。

注意,debug.debug 輸入的命令在文法上並無內嵌到任何函數中, 所以不能直接去訪問局部變量。

 

debug.gethook ([thread])

返回三個表示線程鉤子設置的值: 當前鉤子函數,當前鉤子掩碼,當前鉤子計數 (debug.sethook 設置的那些)。

 

debug.getinfo ([thread,] f [, what])

返回關於一個函數信息的表。 你能夠直接提供該函數, 也能夠用一個數字 f 表示該函數。 數字 f 表示運行在指定線程的調用棧對應層次上的函數: 0 層表示當前函數(getinfo 自身); 1 層表示調用 getinfo 的函數 (除非是尾調用,這種狀況不計入棧);等等。 若是 f 是一個比活動函數數量還大的數字, getinfo 返回 nil

只有字符串 what 中有描述要填充哪些項, 返回的表能夠包含 lua_getinfo 能返回的全部項。 what 默認是返回提供的除合法行號表外的全部信息。 對於選項 'f' ,會在可能的狀況下,增長 func 域保存函數自身。 對於選項 'L' ,會在可能的狀況下,增長 activelines 域保存合法行號表。

例如,表達式 debug.getinfo(1,"n") 返回帶有當前函數名字信息的表(若是找的到名字的話), 表達式 debug.getinfo(print) 返回關於 print 函數的 包含有全部能提供信息的表。

 

debug.getlocal ([thread,] f, local)

此函數返回在棧的 f 層處函數的索引爲 local 的局部變量 的名字和值。 這個函數不只用於訪問顯式定義的局部變量,也包括形參、臨時變量等。

第一個形參或是定義的第一個局部變量的索引爲 1 , 而後遵循在代碼中定義次序,以次類推。 其中只計算函數當前做用域的活動變量。 負索引指可變參數; -1 指第一個可變參數。 若是該索引處沒有變量,函數返回 nil。 若指定的層次越界,拋出錯誤。 (你能夠調用 debug.getinfo 來檢查層次是否合法。)

以 '(' (開括號)打頭的變量名錶示沒有名字的變量 (好比是循環控制用到的控制變量, 或是去除了調試信息的代碼塊)。

參數 f 也能夠是一個函數。 這種狀況下,getlocal 僅返回函數形參的名字。

 

debug.getmetatable (value)

返回給定 value 的元表。 若其沒有元表則返回 nil 。

 

debug.getregistry ()

返回註冊表(參見 §4.5)。

 

debug.getupvalue (f, up)

此函數返回函數 f 的第 up 個上值的名字和值。 若是該函數沒有那個上值,返回 nil 。

以 '(' (開括號)打頭的變量名錶示沒有名字的變量 (去除了調試信息的代碼塊)。

 

debug.getuservalue (u)

返回關聯在 u 上的 Lua 值。 若是 u 並不是用戶數據,返回 nil

 

debug.sethook ([thread,] hook, mask [, count])

將一個函數做爲鉤子函數設入。 字符串 mask 以及數字 count 決定了鉤子將在什麼時候調用。 掩碼是由下列字符組合成的字符串,每一個字符有其含義:

  • 'c': 每當 Lua 調用一個函數時,調用鉤子;
  • 'r': 每當 Lua 從一個函數內返回時,調用鉤子;
  • 'l': 每當 Lua 進入新的一行時,調用鉤子。

此外, 傳入一個不爲零的 count , 鉤子將在每運行 count 條指令時調用。

若是不傳入參數, debug.sethook 關閉鉤子。

當鉤子被調用時, 第一個參數是觸發此次調用的事件: "call" (或 "tail call"), "return", "line", "count"。 對於行事件, 鉤子的第二個參數是新的行號。 在鉤子內,你能夠調用 getinfo ,指定第 2 層, 來得到正在運行的函數的詳細信息 (0 層指 getinfo 函數, 1 層指鉤子函數)。

 

debug.setlocal ([thread,] level, local, value)

這個函數將 value 賦給 棧上第 level 層函數的第 local 個局部變量。 若是沒有那個變量,函數返回 nil 。 若是 level 越界,拋出一個錯誤。 (你能夠調用 debug.getinfo 來檢查層次是否合法。) 不然,它返回局部變量的名字。

關於變量索引和名字,參見 debug.getlocal

 

debug.setmetatable (value, table)

將 value 的元表設爲 table (能夠是 nil)。 返回 value

 

debug.setupvalue (f, up, value)

這個函數將 value 設爲函數 f 的第 up 個上值。 若是函數沒有那個上值,返回 nil 不然,返回該上值的名字。

 

debug.setuservalue (udata, value)

將 value 設爲 udata 的關聯值。 udata 必須是一個徹底用戶數據。

返回 udata

 

debug.traceback ([thread,] [message [, level]])

若是 message 有,且不是字符串或 nil, 函數不作任何處理直接返回 message。 不然,它返回調用棧的棧回溯信息。 字符串可選項 message 被添加在棧回溯信息的開頭。 數字可選項 level 指明從棧的哪一層開始回溯 (默認爲 1 ,即調用 traceback 的那裏)。

 

debug.upvalueid (f, n)

返回指定函數第 n 個上值的惟一標識符(一個輕量用戶數據)。

這個惟一標識符可讓程序檢查兩個不一樣的閉包是否共享了上值。 若 Lua 閉包之間共享的是同一個上值 (即指向一個外部局部變量),會返回相同的標識符。

 

debug.upvaluejoin (f1, n1, f2, n2)

讓 Lua 閉包 f1 的第 n1 個上值 引用 Lua 閉包 f2 的第 n2 個上值。

7 – 獨立版 Lua

雖然 Lua 被設計成一門擴展式語言,用於嵌入一個宿主程序。 但常常也會被當成獨立語言使用。 獨立版的 Lua 語言解釋器隨標準包發佈,就叫 lua。 獨立版解釋器保留了全部的標準庫及調試庫。 其命令行用法爲:

     lua [options] [script [args]]

選項有:

  • -e stat執行一段字符串 stat ;
  • -l mod「請求模塊」 mod ;
  • -i在運行完 腳本 後進入交互模式;
  • -v打印版本信息;
  • -E忽略環境變量;
  • --停止對後面選項的處理;
  • -把 stdin 看成一個文件運行,並停止對後面選項的處理。

在處理完選項後,lua 運行指定的 腳本。 若是不帶參數調用, 在標準輸入(stdin)是終端時,lua 的行爲和 lua -v -i 相同。 不然至關於 lua - 。

若是調用時不帶選項 -E, 解釋器會在運行任何參數前,檢查環境變量 LUA_INIT_5_3 (或在版本名未定義時,檢查 LUA_INIT )。 若是該變量內存格式爲 @filename, lua執行該文件。 不然,lua 執行該字符串。

若是調用時有選項 -E, 除了忽略 LUA_INIT 外, Lua 還忽略 LUA_PATH 與 LUA_CPATH 的值。 將 package.path 和 package.cpath 的值設爲定義在 luaconf.h 中的默認路徑。

除 -i 與 -E 外全部的選項都按次序處理。 例如,這樣調用

     $ lua -e'a=1' -e 'print(a)' script.lua

將先把 a 設爲 1,而後打印 a 的值, 最後運行文件 script.lua 並不帶參數。 (這裏的 $ 是命令行提示。你的命令行提示可能不同。)

在運行任何代碼前, lua 會將全部命令行傳入的參數放到一張全局表 arg 中。 腳本的名字放在索引 0 的地方, 腳本名後緊跟的第一個參數在索引 1 處,依次類推。 在腳本名前面的任何參數 (即解釋器的名字以及各選項) 放在負索引處。 例如,調用

     $ lua -la b.lua t1 t2

這張表是這樣的:

     arg = { [-2] = "lua", [-1] = "-la",
             [0] = "b.lua",
             [1] = "t1", [2] = "t2" }

若是調用中沒提供腳本名, 解釋器的名字就放在索引 0 處,後面接着其它參數。 例如,調用

     $ lua -e "print(arg[1])"

將打印出 "-e" 。 若是提供了腳本名, 就以 arg[1], ···, arg[#arg] 爲參數調用腳本。 (和 Lua 全部的代碼塊同樣, 腳本被編譯成一個可變參數函數。)

在交互模式下, Lua 不斷的顯示提示符,並等待下一行輸入。 一旦讀到一行, 首先試着把這行解釋爲一個表達式。 若是成功解釋,就打印表達式的值。 不然,將這行解釋爲語句。 若是你寫了一行未完成的語句, 解釋器會用一個不一樣的提示符來等待你寫完。

當腳本中出現了未保護的錯誤, 解釋器向標準錯誤流報告錯誤。 若是錯誤對象並不是一個字符串,可是卻有元方法 __tostring 的話, 解釋器會調用這個元方法生成最終的消息。 不然,解釋器將錯誤對象轉換爲一個字符串,並把棧回溯信息加在前面。

若是正常結束運行, 解釋器會關閉主 Lua 狀態機 (參見 lua_close)。 腳本能夠經過調用 os.exit 來結束,以迴避這個步驟。

爲了讓 Lua 能夠用於 Unix 系統的腳本解釋器。 獨立版解釋器會忽略代碼塊的以 # 打頭的第一行。 所以,Lua 腳本能夠經過 chmod +x 以及 #! 形式變成一個可執行文件。 相似這樣

     #!/usr/local/bin/lua

(固然, Lua 解釋器的位置對於你的機器來講可能不同。 若是 lua 在你的 PATH 中, 寫成

     #!/usr/bin/env lua

更爲通用。)

8 – 與以前版本不兼容的地方

這裏咱們列出了把程序從 Lua 5.2 遷移到 Lua 5.3 會碰到的不兼容的地方。 你能夠在編譯 Lua 時定義一些恰當的選項(參見文件 luaconf.h), 來回避一些不兼容性。 然而,這些兼容選項之後會移除。

Lua 的版本更替老是會修改一些 C API 並涉及源代碼的改變。 例如一些常量的數字值,用宏來實現一些函數。 所以,你不能假設在不一樣的 Lua 版本間能夠作到二進制兼容。 當你使用新版時,必定要將使用了 Lua API 的客戶程序從新編譯。

一樣,Lua 版本更替還會改變預編譯代碼塊的內部呈現方式; 在不一樣的 Lua 版本間,預編譯代碼塊不兼容。

官方發佈版的標準路徑也可能隨版本變化。

8.1 – 語言的變動

  • Lua 5.2 到 Lua 5.3 最大的變化是引入了數字的整數子類型。 雖然這個變化不會影響「通常」計算, 但一些計算 (主要是涉及溢出的) 會獲得不一樣的結果。

    你能夠經過把數字都強制轉換爲浮點數來消除差別 (在 Lua 5.2 中,全部的數字都是浮點數)。 好比你能夠將全部的常量都以 .0 結尾, 或是使用 x = x + 0.0 來轉換一個變量。 (這條建議僅用於偶爾快速解決一些不兼容問題; 這不是一條好的編程準則。 好好寫程序的話,你應該在須要使用浮點數的地方用浮點數, 須要整數的地方用整數。)

  • 把浮點數轉爲字符串的地方,如今都對等於整數的浮點數加了 .0 後綴。 (例如,浮點數 2.0 會被打印成 2.0, 而不是 2。) 若是你須要定製數字的格式,就必須顯式的格式化它們。

    (準確說這個不是兼容性問題, 由於 Lua 並無規定數字如何格式化成字符串, 但一些程序假定遵循某種特別的格式。)

  • 分代垃圾收集器沒有了。 (它是 Lua 5.2 中的一個試驗性特性。)

8.2 – 庫的變動

    • bit32 庫廢棄了。 使用一個外部兼容庫很容易, 不過最好直接用對應的位操做符來替換它。 (注意 bit32 只能針對 32 位整數運算, 而標準 Lua 中的位操做能夠用於 64 位整數。)
    • 表處理庫如今在讀寫其中的元素時會考慮元方法。
    • ipairs 這個迭代器也會考慮元方法,而 __ipairs 元方法被廢棄了。
    • io.read 的選項名再也不用 '*' 打頭。 但出於兼容性考慮,Lua 會繼續忽略掉這個字符。
    • 數學庫中的這些函數廢棄了: atan2, cosh, sinh, tanh, pow, frexp, 以及 ldexp 。 你能夠用 x^y 替換 math.pow(x,y); 你能夠用 math.atan 替換math.atan2,前者如今能夠接收一或兩個參數; 你能夠用 x * 2.0^exp 替換 math.ldexp(x,exp)。 若用到其它操做,你能夠寫一個擴展庫,或在 Lua 中實現它們。
  • require 在搜索 C 加載器時處理版本號的方式有所變化。 如今,版本號應該跟在模塊名後(其它大多數工具都是這樣乾的)。 出於兼容性考慮,若是使用新格式找不到加載器的話,搜索器依然會嘗試舊格式。 (Lua 5.2 已是這樣處理了,可是並無寫在文檔裏。)

8.3 – API 的變動

  • 延續函數如今接收原來用 lua_getctx 獲取的參數, 因此 lua_getctx 就去掉了。 按須要改寫你的代碼。
  • 函數 lua_dump 有了一個額外的參數 strip。 若是想和以前的行爲一致,這個值傳 0 。
  • 用於傳入傳出無符號整數的函數 (lua_pushunsigned, lua_tounsigned, lua_tounsignedx, luaL_checkunsigned, luaL_optunsigned) 都廢棄了。 直接從有符號版作類型轉換。
  • 處理輸入非默認整數類型的宏 (luaL_checkint, luaL_optint, luaL_checklong, luaL_optlong) 廢棄掉了。 直接使用 lua_Integer 加一個類型轉換就能夠替代 (或是隻要有可能,就在你的代碼中使用 lua_Integer)。

9 – Lua 的完整語法

這是一份採用擴展 BNF 描述的 Lua 完整語法。 在擴展 BNF 中, {A} 表示 0 或多個 A , [A] 表示一個可選的 A 。 (操做符優先級,參見 §3.4.8; 對於最終符號,名字,數字,字符串字面量的解釋,參見 §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 | ‘#’ | ‘~
相關文章
相關標籤/搜索