# 6 – 標準庫
標準庫提供了一些有用的函數, 它們都是直接用 C API 實現的。 其中一些函數提供了原本語言就有的服務 (例如,[`type`](#pdf-type) 與 [`getmetatable`](#pdf-getmetatable)); 另一些提供和“外部”打交道的服務(例如 I/O ); 還有些本可以用 Lua 本身來實現,但在 C 中實現可以滿足關鍵點上的性能需求 (例如 [`table.sort`](#pdf-table.sort))。
所有的庫都是直接用 C API 實現的,并以分離的 C 模塊形式提供。 目前,Lua 有下列標準庫:
* 基礎庫 ([§6.1](#6.1));
* 協程庫 ([§6.2](#6.2));
* 包管理庫 ([§6.3](#6.3));
* 字符串控制 ([§6.4](#6.4));
* 基礎 UTF-8 支持 ([§6.5](#6.5));
* 表控制 ([§6.6](#6.6));
* 數學函數 ([§6.7](#6.7)) (sin ,log 等);
* 輸入輸出 ([§6.8](#6.8));
* 操作系統庫 ([§6.9](#6.9));
* 調試庫 ([§6.10](#6.10)).
除了基礎庫和包管理庫, 其它庫都把自己的函數放在一張全局表的域中, 或是以對象方法的形式提供。
要使用這些庫, C 的宿主程序需要先調用一下 [`luaL_openlibs`](#luaL_openlibs) 這個函數, 這樣就能打開所有的標準庫。 或者宿主程序也可以用 [`luaL_requiref`](#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`](#pdf-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](#2.5))。 返回 _間歇率_ 的前一個值。
* **"`setstepmul`":** 將 `arg` 設為收集器的 _步進倍率_ (參見 [§2.5](#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](#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](#2.2)))。 然而,如果你加載一個用函數(參見 [`string.dump`](#pdf-string.dump), 結果函數可以有任意數量的上值) 創建出來的二進制代碼塊時,所有的上值都是新創建出來的。 也就是說它們不會和別的任何函數共享。
`chunkname` 在錯誤消息和調試消息中(參見 [§4.9](#4.9)),用于代碼塊的名字。 如果不提供此參數,它默認為字符串`chunk` 。 `chunk` 不是字符串時,則為 "`=(load)`" 。
字符串 `mode` 用于控制代碼塊是文本還是二進制(即預編譯代碼塊)。 它可以是字符串 "`b`" (只能是二進制代碼塊), "`t`" (只能是文本代碼塊), 或 "`bt`" (可以是二進制也可以是文本)。 默認值為 "`bt`"。
Lua 不會對二進制代碼塊做健壯性檢查。 惡意構造一個二進制塊有可能把解釋器弄崩潰。
### `loadfile ([filename [, mode [, env]]])`
和 [`load`](#pdf-load) 類似, 不過是從文件 `filename` 或標準輸入(如果文件名未提供)中獲取代碼塊。
### `next (table [, index])`
運行程序來遍歷表中的所有域。 第一個參數是要遍歷的表,第二個參數是表中的某個鍵。 `next` 返回該鍵的下一個鍵及其關聯的值。 如果用 **nil** 作為第二個參數調用 `next` 將返回初始鍵及其關聯值。 當以最后一個鍵去調用,或是以 **nil** 調用一張空表時, `next` 返回 **nil**。 如果不提供第二個參數,將認為它就是 **nil**。 特別指出,你可以用 `next(t)` 來判斷一張表是否是空的。
索引在遍歷過程中的次序無定義, _即使是數字索引也是這樣_。 (如果想按數字次序遍歷表,可以使用數字形式的 **for** 。)
當在遍歷過程中你給表中并不存在的域賦值, `next` 的行為是未定義的。 然而你可以去修改那些已存在的域。 特別指出,你可以清除一些已存在的域。
### `pairs (t)`
如果 `t` 有元方法 `__pairs`, 以 `t` 為參數調用它,并返回其返回的前三個值。
否則,返回三個值:[`next`](#pdf-next) 函數, 表 `t`,以及 **nil**。 因此以下代碼
```
for k,v in pairs(t) do _body_ end
```
能迭代表 `t` 中的所有鍵值對。
參見函數 [`next`](#pdf-next) 中關于迭代過程中修改表的風險。
### `pcall (f [, arg1, ···])`
傳入參數,以 _保護模式_ 調用函數 `f` 。 這意味著 `f` 中的任何錯誤不會拋出; 取而代之的是,`pcall` 會將錯誤捕獲到,并返回一個狀態碼。 第一個返回值是狀態碼(一個布爾量), 當沒有錯誤時,其為真。 此時,`pcall` 同樣會在狀態碼后返回所有調用的結果。 在有錯誤時,`pcall` 返回 **false** 加錯誤消息。
### `print (···)`
接收任意數量的參數,并將它們的值打印到 `stdout`。 它用 [`tostring`](#pdf-tostring) 函數將每個參數都轉換為字符串。 `print` 不用于做格式化輸出。僅作為看一下某個值的快捷方式。 多用于調試。 完整的對輸出的控制,請使用 [`string.format`](#pdf-string.format) 以及 [`io.write`](#pdf-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](#3.1))。 (字符串可以有前置和后置的空格,可以帶符號。)
當傳入 `base` 調用它時, `e` 必須是一個以該進制表示的整數字符串。 進制可以是 2 到 36 (包含 2 和 36)之間的任何整數。 大于 10 進制時,字母 '`A`' (大小寫均可)表示 10 , '`B`' 表示 11,依次到 '`Z`' 表示 35 。 如果字符串 `e` 不是該進制下的合法數字, 函數返回 **nil**。
### `tostring (v)`
可以接收任何類型,它將其轉換為人可閱讀的字符串形式。 浮點數總被轉換為浮點數的表現形式(小數點形式或是指數形式)。 (如果想完全控制數字如何被轉換,可以使用 [`string.format`](#pdf-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`](#pdf-pcall) 類似。 不過它可以額外設置一個消息處理器 `msgh`。
## 6.2 – 協程管理
關于協程的操作作為基礎庫的一個子庫, 被放在一個獨立表 `coroutine` 中。 協程的介紹參見 [§2.6](#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`](#pdf-require)。 所有其它的部分都導出在表 `package` 中。
### `require (modname)`
加載一個模塊。 這個函數首先查找 [`package.loaded`](#pdf-package.loaded) 表, 檢測 `modname` 是否被加載過。 如果被加載過,`require` 返回 `package.loaded[modname]` 中保存的值。 否則,它試著為模塊尋找 _加載器_ 。
`require` 遵循 [`package.searchers`](#pdf-package.searchers) 序列的指引來查找加載器。 如果改變這個序列,我們可以改變 `require` 如何查找一個模塊。 下列說明基于 [`package.searchers`](#pdf-package.searchers) 的默認配置。
首先 `require` 查找 `package.preload[modname]` 。 如果這里有一個值,這個值(必須是一個函數)就是那個加載器。 否則 `require` 使用 Lua 加載器去查找 [`package.path`](#pdf-package.path) 的路徑。 如果查找失敗,接著使用 C 加載器去查找 [`package.cpath`](#pdf-package.cpath) 的路徑。 如果都失敗了,再嘗試 _一體化_ 加載器 (參見 [`package.searchers`](#pdf-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`](#pdf-require) 在 C 加載器中做搜索時用到。
Lua 用和初始化 Lua 路徑 [`package.path`](#pdf-package.path) 相同的方式初始化 C 路徑 [`package.cpath`](#pdf-package.cpath) 。 它會使用環境變量 `LUA_CPATH_5_3` 或 環境變量 `LUA_CPATH` 初始化。 要么就采用 `luaconf.h` 中定義的默認路徑。
### `package.loaded`
用于 [`require`](#pdf-require) 控制哪些模塊已經被加載的表。 當你請求一個 `modname` 模塊,且 `package.loaded[modname]` 不為假時, [`require`](#pdf-require) 簡單返回儲存在內的值。
這個變量僅僅是對真正那張表的引用; 改變這個值并不會改變 [`require`](#pdf-require) 使用的表。
### `package.loadlib (libname, funcname)`
讓宿主程序動態鏈接 C 庫 `libname` 。
當 `funcname` 為 "`*`", 它僅僅連接該庫,讓庫中的符號都導出給其它動態鏈接庫使用。 否則,它查找庫中的函數 `funcname` ,以 C 函數的形式返回這個函數。 因此,`funcname` 必須遵循原型 [`lua_CFunction`](#lua_CFunction) (參見 [`lua_CFunction`](#lua_CFunction))。
這是一個低階函數。 它完全繞過了包模塊系統。 和 [`require`](#pdf-require) 不同, 它不會做任何路徑查詢,也不會自動加擴展名。 `libname` 必須是一個 C 庫需要的完整的文件名,如果有必要,需要提供路徑和擴展名。 `funcname` 必須是 C 庫需要的準確名字 (這取決于使用的 C 編譯器和鏈接器)。
這個函數在標準 C 中不支持。 因此,它只在部分平臺有效 ( Windows ,Linux ,Mac OS X, Solaris, BSD, 加上支持 `dlfcn` 標準的 Unix 系統)。
### `package.path`
這個路徑被 [`require`](#pdf-require) 在 Lua 加載器中做搜索時用到。
在啟動時,Lua 用環境變量 `LUA_PATH_5_3` 或環境變量 `LUA_PATH` 來初始化這個變量。 或采用 `luaconf.h` 中的默認路徑。 環境變量中出現的所有 "`;;`" 都會被替換成默認路徑。
### `package.preload`
保存有一些特殊模塊的加載器 (參見 [`require`](#pdf-require))。
這個變量僅僅是對真正那張表的引用; 改變這個值并不會改變 [`require`](#pdf-require) 使用的表。
### `package.searchers`
用于 [`require`](#pdf-require) 控制如何加載模塊的表。
這張表內的每一項都是一個 _查找器函數_。 當查找一個模塊時, [`require`](#pdf-require) 按次序調用這些查找器, 并傳入模塊名([`require`](#pdf-require) 的參數)作為唯一的一個參數。 此函數可以返回另一個函數(模塊的 _加載器_)加上另一個將傳遞給這個加載器的參數。 或是返回一個描述為何沒有找到這個模塊的字符串 (或是返回 **nil** 什么也不想說)。
Lua 用四個查找器函數初始化這張表。
第一個查找器就是簡單的在 [`package.preload`](#pdf-package.preload) 表中查找加載器。
第二個查找器用于查找 Lua 庫的加載庫。 它使用儲存在 [`package.path`](#pdf-package.path) 中的路徑來做查找工作。 查找過程和函數 [`package.searchpath`](#pdf-package.searchpath) 描述的一致。
第三個查找器用于查找 C 庫的加載庫。 它使用儲存在 [`package.cpath`](#pdf-package.path) 中的路徑來做查找工作。 同樣, 查找過程和函數 [`package.searchpath`](#pdf-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`](#pdf-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`](#pdf-string.sub) 的規則修正。
數字編碼沒有必要跨平臺。
### `string.char (···)`
接收零或更多的整數。 返回和參數數量相同長度的字符串。 其中每個字符的內部編碼值等于對應的參數值。
數字編碼沒有必要跨平臺。
### `string.dump (function [, strip])`
返回包含有以二進制方式表示的(一個 _二進制代碼塊_ )指定函數的字符串。 之后可以用 [`load`](#pdf-load) 調用這個字符串獲得 該函數的副本(但是綁定新的上值)。 如果 `strip` 為真值, 二進制代碼塊不攜帶該函數的調試信息 (局部變量名,行號,等等。)。
帶上值的函數只保存上值的數目。 當(再次)加載時,這些上值被更新為 **nil** 的實例。 (你可以使用調試庫按你需要的方式來序列化上值,并重載到函數中)
### `string.find (s, pattern [, init [, plain]])`
查找第一個字符串 `s` 中匹配到的 `pattern` (參見 [§6.4.1](#6.4.1))。 如果找到一個匹配,`find` 會返回 `s` 中關于它起始及終點位置的索引; 否則,返回 **nil**。 第三個可選數字參數 `init` 指明從哪里開始搜索; 默認值為 1 ,同時可以是負值。 第四個可選參數 `plain` 為 **true** 時, 關閉模式匹配機制。 此時函數僅做直接的 “查找子串”的操作, 而 `pattern` 中沒有字符被看作魔法字符。 注意,如果給定了 `plain` ,就必須寫上 `init` 。
如果在模式中定義了捕獲,捕獲到的若干值也會在兩個索引之后返回。
### `string.format (formatstring, ···)`
返回不定數量參數的格式化版本, 格式化串為第一個參數(必須是一個字符串)。 格式化字符串遵循 ISO C 函數 `sprintf` 的規則。 不同點在于選項 `*`, `h`, `L`, `l`, `n`, `p` 不支持, 另外還增加了一個選項 `q`。 `q` 選項將一個字符串格式化為兩個雙引號括起,對內部字符做恰當的轉義處理的字符串。 該字符串可以安全的被 Lua 解釋器讀回來。 例如,調用
```
string.format('%q', 'a string with "quotes" and \n new line')
```
會產生字符串:
```
"a string with \"quotes\" and \
new line"
```
選項 `A` and `a` (如果有的話), `E`, `e`, `f`, `G`, and `g` 都期待一個對應的數字參數。 選項 `c`, `d`, `i`, `o`, `u`, `X`, and `x` 則期待一個整數。 選項 `q` 期待一個字符串; 選項 `s` 期待一個沒有內嵌零的字符串。 如果選項 `s` 對應的參數不是字符串,它會用和 [`tostring`](#pdf-tostring) 一致的規則轉換成字符串。
### `string.gmatch (s, pattern)`
返回一個迭代器函數。 每次調用這個函數都會繼續以 `pattern` (參見 [§6.4.1](#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](#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](#6.4.1))匹配到的部分。 如果能找到,`match` 返回其中的捕獲物; 否則返回 **nil** 。 如果 `pattern` 中未指定捕獲, 返回整個 `pattern` 捕獲到的串。 第三個可選數字參數 `init` 指明從哪里開始搜索; 它默認為 1 且可以是負數。
### `string.pack (fmt, v1, v2, ···)`
返回一個打包了(即以二進制形式序列化) `v1`, `v2` 等值的二進制字符串。 字符串 `fmt` 為打包格式(參見 [§6.4.2](#6.4.2))。
### `string.packsize (fmt)`
返回以指定格式用 [`string.pack`](#pdf-string.pack) 打包的字符串的長度。 格式化字符串中不可以有變長選項 '`s`' 或 '`z`' (參見 [§6.4.2](#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](#6.4.2)) 打包在字符串 `s` (參見 [`string.pack`](#pdf-string.pack)) 中的值。 選項 `pos`(默認為 1 )標記了從 `s` 中哪里開始讀起。 讀完所有的值后,函數返回 `s` 中第一個未讀字節的位置。
### `string.upper (s)`
接收一個字符串,將其中的小寫字符都轉為大寫后返回其副本。 其它的字符串不會更改。 對小寫字符的定義取決于當前的區域設置。
### 6.4.1 – 匹配模式
Lua 中的匹配模式直接用常規的字符串來描述。 它用于模式匹配函數 [`string.find`](#pdf-string.find), [`string.gmatch`](#pdf-string.gmatch), [`string.gsub`](#pdf-string.gsub), [`string.match`](#pdf-string.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_ 號捕獲物(后面有描述)的子串。
* `%b_xy_`, 這里的 _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`](#pdf-string.pack), [`string.packsize`](#pdf-string.packsize), [`string.unpack`](#pdf-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`
* **`c_n_`:** `n`字節固定長度的字符串
* **`z`:** 零結尾的字符串
* **`s[_n_]`:** 長度加內容的字符串,其長度編碼為一個 `n` 字節(默認是個 `size_t`) 長的無符號整數。
* **`x`:** 一個字節的填充
* **`X_op_`:** 按選項 `op` 的方式對齊(忽略它的其它方面)的一個空條目
* **'':** (空格)忽略
( "`[_n_]`" 表示一個可選的整數。) 除填充、空格、配置項(選項 "`xX <=>!`")外, 每個選項都關聯一個參數(對于 [`string.pack`](#pdf-string.pack)) 或結果(對于 [`string.unpack`](#pdf-string.unpack))。
對于選項 "`!_n_`", "`s_n_`", "`i_n_`", "`I_n_`", `n` 可以是 1 到 16 間的整數。 所有的整數選項都將做溢出檢查; [`string.pack`](#pdf-string.pack) 檢查提供的值是否能用指定的字長表示; [`string.unpack`](#pdf-string.unpack) 檢查讀出的值能否置入 Lua 整數中。
任何格式串都假設有一個 "`!1=`" 前綴, 即最大對齊為 1 (無對齊)且采用本地大小端設置。
對齊行為按如下規則工作: 對每個選項,格式化時都會填充一些字節直到數據從一個特定偏移處開始, 這個位置是該選項的大小和最大對齊數中較小的那個數的倍數; 這個較小值必須是 2 個整數次方。 選項 "`c`" 及 "`z`" 不做對齊處理; 選項 "`s`" 對對齊遵循其開頭的整數。
[`string.pack`](#pdf-string.pack) 用零去填充 ([`string.unpack`](#pdf-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](#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](#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.ceil`](#pdf-math.ceil), [`math.floor`](#pdf-math.floor), [`math.modf`](#pdf-math.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)`
返回 _e<sup>x</sup>_ 的值 (`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`](#pdf-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`](#pdf-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`](#pdf-io.popen) 創建出來的文件句柄時, [`file:close`](#pdf-file:close) 返回 [`os.execute`](#pdf-os.execute) 會返回的一樣的值。
### `file:flush ()`
將寫入的數據保存到 `file` 中。
### `file:lines (···)`
返回一個迭代器函數, 每次調用迭代器時,都從文件中按指定格式讀數據。 如果沒有指定格式,使用默認值 "`l`" 。 看一個例子
```
for c in file:lines(1) do _body_ end
```
會從文件當前位置開始,中不斷讀出字符。 和 [`io.lines`](#pdf-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`](#pdf-io.flush)) 時才真正做輸出操作。
* **"`line`":** 行緩沖; 輸出將到每次換行前, 對于某些特殊文件(例如終端設備)緩沖到任何輸入前。
對于后兩種情況,`size` 以字節數為單位 指定緩沖區大小。 默認會有一個恰當的大小。
### `file:write (···)`
將參數的值逐個寫入 `file`。 參數必須是字符串或數字。
成功時,函數返回 `file`。 否則返回 **nil** 加錯誤描述字符串。
## 6.9 – 操作系統庫
這個庫都通過表 `os` 實現。
### `os.clock ()`
返回程序使用的按秒計 CPU 時間的近似值。
### `os.date ([format [, time]])`
返回一個包含日期及時刻的字符串或表。 格式化方法取決于所給字符串 `format`。
如果提供了 `time` 參數, 格式化這個時間 (這個值的含義參見 [`os.time`](#pdf-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`](#pdf-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])`
當不傳參數時,返回當前時刻。 如果傳入一張表,就返回由這張表表示的時刻。 這張表必須包含域 `year`,`month`,及 `day`; 可以包含有 `hour` (默認為 12 ), `min` (默認為 0), `sec` (默認為 0),以及 `isdst` (默認為 **nil**)。 關于這些域的詳細描述,參見 [`os.date`](#pdf-os.date) 函數。
返回值是一個含義由你的系統決定的數字。 在 POSIX,Windows,和其它一些系統中, 這個數字統計了從指定時間("epoch")開始經歷的秒數。 對于另外的系統,其含義未定義, 你只能把 `time` 的返回數字用于 [`os.date`](#pdf-os.date) 和 [`os.difftime`](#pdf-os.difftime) 的參數。
### `os.tmpname ()`
返回一個可用于臨時文件的文件名字符串。 這個文件在使用前必須顯式打開,不再使用時需要顯式刪除。
在 POSIX 系統上, 這個函數會以此文件名創建一個文件以回避安全風險。 (別人可能未經允許在獲取到這個文件名到創建該文件之間的時刻創建此文件。) 你依舊需要在使用它的時候先打開,并最后刪除(即使你沒使用到)。
只有有可能,你更應該使用 [`io.tmpfile`](#pdf-io.tmpfile), 因為該文件可以在程序結束時自動刪除。
## 6.10 – 調試庫
這個庫提供了 Lua 程序調試接口([§4.9](#4.9))的功能。 其中一些函數違反了 Lua 代碼的基本假定 (例如,不會從函數之外訪問函數的局部變量; 用戶數據的元表不會被 Lua 代碼修改; Lua 程序不會崩潰), 因此它們有可能危害到其它代碼的安全性。 此外,庫里的一些函數可能運行的很慢。
這個庫里的所有函數都提供在表 `debug` 內。 所有操作線程的函數,可選的第一個參數都是針對的線程。 默認值永遠是當前線程。
### `debug.debug ()`
進入一個用戶交互模式,運行用戶輸入的每個字符串。 使用簡單的命令以及其它調試設置,用戶可以檢閱全局變量和局部變量, 改變變量的值,計算一些表達式,等等。 輸入一行僅包含 `cont` 的字符串將結束這個函數, 這樣調用者就可以繼續向下運行。
注意,`debug.debug` 輸入的命令在文法上并沒有內嵌到任何函數中, 因此不能直接去訪問局部變量。
### `debug.gethook ([thread])`
返回三個表示線程鉤子設置的值: 當前鉤子函數,當前鉤子掩碼,當前鉤子計數 ([`debug.sethook`](#pdf-debug.sethook) 設置的那些)。
### `debug.getinfo ([thread,] f [, what])`
返回關于一個函數信息的表。 你可以直接提供該函數, 也可以用一個數字 `f` 表示該函數。 數字 `f` 表示運行在指定線程的調用棧對應層次上的函數: 0 層表示當前函數(`getinfo` 自身); 1 層表示調用 `getinfo` 的函數 (除非是尾調用,這種情況不計入棧);等等。 如果 `f` 是一個比活動函數數量還大的數字, `getinfo` 返回 **nil**。
只有字符串 `what` 中有描述要填充哪些項, 返回的表可以包含 [`lua_getinfo`](#lua_getinfo) 能返回的所有項。 `what` 默認是返回提供的除合法行號表外的所有信息。 對于選項 '`f`' ,會在可能的情況下,增加 `func` 域保存函數自身。 對于選項 '`L`' ,會在可能的情況下,增加 `activelines` 域保存合法行號表。
例如,表達式 `debug.getinfo(1,"n")` 返回帶有當前函數名字信息的表(如果找的到名字的話), 表達式 `debug.getinfo(print)` 返回關于 [`print`](#pdf-print) 函數的 包含有所有能提供信息的表。
### `debug.getlocal ([thread,] f, local)`
此函數返回在棧的 `f` 層處函數的索引為 `local` 的局部變量 的名字和值。 這個函數不僅用于訪問顯式定義的局部變量,也包括形參、臨時變量等。
第一個形參或是定義的第一個局部變量的索引為 1 , 然后遵循在代碼中定義次序,以次類推。 其中只計算函數當前作用域的活動變量。 負索引指可變參數; -1 指第一個可變參數。 如果該索引處沒有變量,函數返回 **nil**。 若指定的層次越界,拋出錯誤。 (你可以調用 [`debug.getinfo`](#pdf-debug.getinfo) 來檢查層次是否合法。)
以 '`(`' (開括號)打頭的變量名表示沒有名字的變量 (比如是循環控制用到的控制變量, 或是去除了調試信息的代碼塊)。
參數 `f` 也可以是一個函數。 這種情況下,`getlocal` 僅返回函數形參的名字。
### `debug.getmetatable (value)`
返回給定 `value` 的元表。 若其沒有元表則返回 **nil** 。
### `debug.getregistry ()`
返回注冊表(參見 [§4.5](#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`](#pdf-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`](#pdf-debug.getinfo) 來檢查層次是否合法。) 否則,它返回局部變量的名字。
關于變量索引和名字,參見 [`debug.getlocal`](#pdf-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` 個上值。