(接上篇)編程
--------------------------------------
5 API
--------------------------------------
這節主要描述 Lua 的 API, 也就是宿主程序和庫交互的一組 C 函數。API 函數能夠分爲如下幾類:
1. 執行 Lua 代碼;
2. 在 Lua 和 C 之間進行值的轉化;
3. 操做(讀寫)Lua 對象;
4. 調用 Lua 函數;
5. 由 Lua 調用的 C 函數;
6. 錯誤處理。
全部的 API 都在文件 lua.h 中聲明。除非另有說明,API 函數返回一個錯誤碼:0 爲成功,非 0 爲失敗。
-------------------
5.1 執行 Lua 代碼
-------------------
一個宿主程序能夠執行寫在文件中或在字符串中的 Lua 代碼,使用下面的函數:
int lua_dofile (char *filename);
int lua_dostring (char *string);
-------------------
5.2 在 Lua 和 C 之間進行值的轉化
-------------------
由於 Lua 沒有靜態的類型系統,全部的在 Lua 和 C 之間傳遞的值的類型爲 lua_Object,它像是 C 中的可保存任何 Lua 值的一個抽象的類型。 lua_Object 聲明以下:
typedef struct Object *lua_Object;
Object 沒有在 lua.h 中聲明。
Lua 有垃圾回收。因此,不保證在一個 lua_Object 是可用的在執行了其它的 Lua 代碼以後。一個好的編程實踐是在這些值可用的時候把它轉化爲 C 語言的值,而且永遠不要把它們保存在全局變量中。
可使用下面的函數來檢查一個 lua_Obejct 的類型:
int lua_isnil (lua_Object object);
int lua_isnumber (lua_Object object);
int lua_isstring (lua_Object object);
int lua_istable (lua_Object object);
int lua_iscfunction (lua_Object object);
int lua_isuserdata (lua_Object object);
它們返回 1 若是類型是指定的類型的話, 不然返回 0。
可使用下面的函數把一個 lua_Object 轉化爲 C 類型:
float lua_getnumber (lua_Object object);
char *lua_getstring (lua_Object object);
char *lua_copystring (lua_Object object);
lua_CFunction lua_getcfunction (lua_Object object);
void *lua_getuserdata (lua_Object object);
lua_getnumber 能夠把一個 lua_Obejct 轉化爲一個浮點數。這個 lua_Object 必須是一個數字或者一個能夠轉化爲數字的字符串(見 4.2 節);不然,該函數返回 0。
lua_getstring 把 lua_Object 轉化爲一個 string(char *)。這個 lua_Object 必須是一個字符串或者一個數字;不然,該函數返回 0 (空指針)。該函數不會建立一個新的字符串,它只是返回一個指向 Lua 環境中的字符串的指針。由於 Lua 有垃圾回收,沒有什麼保證這個指針在執行了另外的 Lua 代碼以後依然有效。函數 lua_copystring 表現和 lua_getstring 徹底同樣,可是它返回那個字符串的一個全新拷貝。
lua_getfunction 把 lua_Object 轉化爲一個 C 函數。這個 lua_Obejct 類型必須爲 Cfunction; 不然返回 0 (空指針)。類型 lua_CFunction 在 5.5 節中解釋。
lua_getuserdata 把 lua_Object 轉化爲一個 void *。這個 lua_Obejct 類型必須爲 userdata; 不然返回 0 (空指針)。
相反,把一個 C 類型轉化爲 lua_Obejct 類型用如下的函數:
int lua_pushnumber (float n);
int lua_pushstring (char *s);
int lua_pushcfunction (lua_CFunction f);
int lua_pushuserdata (void *u);
這些函數都接受一個 C 值,把它轉化爲 lua_Object,並把結果保存在 Lua 棧頂,在那裏它能夠被賦值給一個變量,作爲參數傳遞給一個 Lua 函數,等(見下文)。爲了完成設置,nil 或者 lua_Object 也能夠壓棧,用下面的函數:
int lua_pushnil (void);
int lua_pushobject (lua_Object object);
-------------------
5.3 操做Lua 對象
-------------------
可使用如下的函數讀取 Lua 全局變量的值:
lua_Object lua_getglobal (char *varname);
把前先壓到棧頂的一個值保存到一個全局變量,用下面的函數:
int lua_storeglobal (char *varname);
表也能夠經過 API 來操做,給定一個表,函數:
lua_Object lua_getindexed (lua_Object table, float index);
lua_Object lua_getfield (lua_Object table, char *field);
返回索引的內容。第一個用數字索引,第二個用任何的字符串索引。由於在 Lua 中,若是一個索引不在表中的話,返回的 Lua_Object 的值爲 nil。
把前先壓到棧頂的值保存到 Lua 表中的話,可使用如下函數:
int lua_storeindexed (lua_Object object, float index);
int lua_storefield (lua_Object object, char *field);
一樣,第一個用數字索引,第二個用字符串索引。
-------------------
5.4 調用 Lua 函數
-------------------
在宿主程序中能夠調用由模塊執行 dofile 或者 dostring 定義的函數。這採用以下的協議:前行,函數參數壓到 Lua 棧上(詳見 5.2 節),壓棧的順序和參數一致,也就是第一個參數首先壓棧。而後,函數調用能夠用:
int lua_call (char *functionname, int nparam);
第二個參數(nparam)是被壓到棧上的值的個數。最後,返回的值(Lua 函數能夠返回多個值)以逆序出棧,也就是最後一個返回值最早出棧。出棧用下面的函數:
lua_Object lua_pop (void);
當沒有返回值可出棧時,函數返回 0。
7.5 節有一個 C 代碼調用 Lua 函數的例子。
-------------------
5.5 C 函數
-------------------
註冊 C 函數到 Lua ,用下面的宏:
#define lua_register(n,f) (lua_pushcfunction(f), lua_storeglobal(n))
/* char *n; */
/* lua_CFunction f; */
它接受函數在 Lua 中的名字,一個函數指針。這個指針的類型必須爲 lua_CFunction,其定義爲:
typedef void (*lua_CFunction) (void);
也就是一個無參無返回值的函數指針。
爲了和 Lua 正確的交互,C 函數必須遵照一個協議,這個協議規定了參數和返回值傳遞的方法。
爲了獲得它的參數,C 函數調用 :
lua_Object lua_getparam (int number);
number 從 1 開始返回第一個參數。當用一個大於參數實際個數的值來調用時,該函數返回 0。用這種方法,寫可變參數個數的函數就是可行的。
爲了從 C 返回值到 Lua, C 函數能夠把返回值順序壓棧;見 5.2 節。就像 Lua 函數同樣,一個由 Lua 調用的 C 函數也能夠返回多個值。
7.4 節展現了一個 Cfunction 的例子。
-------------------
5.6 錯誤處理
-------------------
當在 Lua 編譯或執行時出現一個錯誤的時候,會調用一個查錯程序,相應的 lua_dofile 或 lua_dostring 會中斷並返回一個出錯狀態。
查錯程序的惟一的一個參數就是一個字符串,它描述了出現的錯誤和一個額外的信息,像當前的行(當錯誤發生在編譯時)或者當前的函數(當錯誤發生在運行時)。錯誤的查錯程序只是打印這個信息到標準錯誤輸出。若是須要的話,能夠給它設置一個新的查錯程序,用下面的函數:
void lua_errorfunction (void (*fn) (char *s));
它的參數是錯誤處理函數的地址。
--------------------------------------
6 預約義的函數和庫
--------------------------------------
Lua 的一組預約義函數雖少但功能強大。他們中大多數提供的功能讓語言有必定程度的自反性。這些功能不能經過語言的其它部分模擬也不能經過標準的 API 模擬。
庫,在另外一方面,提供了一種經過標準 API 實現的有用的程序。所以,它們並不是語言必須的部分,而且做爲單獨的 C 模塊被提供,它能夠根據須要被鏈接到應用程序。
目前,有三個庫:
字符串處理
數學函數(sin, cos, 等)
輸入輸出
預約義函數能處理如下任務:執行包含在一個文件或字符串中的 Lua 模塊;遍歷一個表的全部字段;枚舉全部的全局變量;類型查詢和轉換。
-------------------
6.1 預約義函數
-------------------
dofile (filename)
函數接受一個函數名字,打開並執行它的內容作爲一個 Lua 模塊。它返回 1 若是沒有出錯,不然返回 0。
dostring (string)
函數執行一個給定的字符串作爲一個 Lua 模塊,沒有錯誤返回 1, 不然返回 0。
next (table, index)
函數容許一個程序枚舉一個表的全部字段。它的第一個參數是一個表,第二個參數是表中的索引;這個索引能夠是數字或字符串。它返回表的下一個鍵值對(索引及和索引關聯的值)。當用 nil 作爲第二個參數調用它時,函數返回表的第一個健值對。當用最後一個索引調用,或者用 nil 調用一個空表,均返回 nil。
Lua 中沒有字段的聲明;在語義上,表中一個字段不存在和字段的值爲 nil 沒有區別。因此,該函數只考慮沒有空值的字段。索引的枚舉順序沒有規定,就算是數字索引的也沒有規定。
7.1 節有一個使用這個函數的例子。
nextvar (name)
函數和 next 函數相似,但它在全局變量上遍歷。它的參數是全局變量的名字,或者是 nil (能夠得到第一個名字)。和 next 相似,它返回另外一個變量的名字和值。或者是 nil 若是沒有更多的變量了(遍歷結束了)。
7.1 節 有一個使用這個函數的例子。
print (e1, e2, ...)
函數能夠接受任意數量的參數,以一種合理的格式打印它們的值。每個值都在一個新行上打印。這個函數不是爲了格式化輸出,只是爲了以一種快速的方法顯示一個值,例如打印一個出錯信息或者調試。詳見 6.4 節一個格式化輸出函數。
tonumber (e)
函數接受一個參數,嘗試把它轉化爲一個數字。若是參數已是一個數字或者是一個能夠轉化爲數字的字符串(詳見 4.2 節),它返回那個數字;不然,返回 nil。
type (v)
函數容許 Lua 測試一個值的類型。它接受一個參數,返回它的類型,以一個字符串表示。這個函數可能的返回值是:
'nil'
'number'
'string'
'table'
'cfunction'
'function'
'userdata'
-------------------
6.2 字符串處理
-------------------
這個庫提供字符串處理的通用函數,如查找和提取子串。索引一個字符串的時候,第一個字符的索引是 1。7.2 節有一些字符串處理的例子。
strfind (str, substr)
接受兩個字符串參數,返回一個數字。這個數字標明第二個參數在第一個參數中第一次出現的位置。若是第二個參數不是第一個參數的子串,返回 nil。
strlen (s)
接受一個字符串返回它的長度。
strsub (s, i, j)
返回另外一個字符串,它是 s 的子串,始於 i 終於 j 。 若是 j 不指定或者爲 nil,它被假定爲 s 的長度。特別的,strsub(s,1,j) 調用返回 s 的 j 個字符的前綴,strsub(s,i) 返回 s 的後綴。
strlower (s)
接受一個字符串,返回它的全部大寫字母都轉化爲小寫的拷貝。其它的字符保持不變。
strupper (s)
接受一個字符串,返回它的全部小寫字母都轉化爲大寫的拷貝。其它的字符保持不變。
-------------------
6.3 數學函數
-------------------
這個庫到一些標準 C 函數庫函數的一個接口。它提供瞭如下的函數:
abs acos asin atan ceil cos floor max min
mod pow sin sqrt tan
函數 floor, sqrt, pow, ceil, sin, cos, tan, asin, acos, 和 atan 只是到 C 函數庫中同名函數的接口,不一樣之處是,在三角函數中,全部的角度被轉化爲弧度。
max 返回數字參數列表中的最大值,相似的,min 返回最小值。它們的參數個數都是任意的。
mode 和 C 語言中的 % 操做符是等價的。
-------------------
6.4 I/O
-------------------
Lua 中全部的 I/O 操做都是基於兩個當前文件,一個是爲了讀,一個是爲了寫。當前的輸入輸出文件的初始值分別是 stdin, stdout。
除非特別規定,全部的 I/O 函數功能時返回 1 失敗時返回 nil。
readfrom (filename)
函數打開一個名爲 filename 的文件而且把它設置爲當前的入出文件。當無參調用它時,這個函數把當前的輸入文件恢復爲 stdin。
writeto (filename)
函數打開一個名爲 filename 的文件而且把它設置爲當前的輸出文件。注意,若是這個文件是已經存在,調用這個操做會清除它。當無參調用它時,這個函數把當前的輸出文件恢復爲 stdout。
appendto (filename)
函數打開一個名爲 filename 的文件而且把它設置爲當前的輸出文件。不像 writeto 操做,這個函數不會清除文件以前的內容。當無參調用它時,這個函數把當前的輸出文件恢復爲 stdout。這個函數返回 2 若是文件已經存在,返回 1 若是新建了一個文件,返回 nil 若是失敗。
read ([format])
函數返回從當前輸入讀取的值。一個可選的參數指定輸入的解釋方式。
若是沒有格式化參數,read 首先跳過空白(空格,製表符,換行符)。而後它檢查當前的字符是不是單引號或雙引號(」,’)。若是是,它讀取一個字符串直到字符串結束標誌,而且返回這個字符串,不帶字符串的標誌符。不然,它讀取直到另外一個空白(空格,製表符,換行符)。
格式化字符串能夠是如下的形式:
?[n]
? 能夠是:
's' 或者 'S' 讀一個字符串;
'f' 或者 'F' 讀一個實數;
'i' 或者 'I' 讀一個整數。
可選的 n 是一個數字指示爲了構成輸入而必須讀取多少個字符。
write (value, [format])
函數寫第一個參數的值到當前輸出。可選的第二個參數指示使用格式。這個格式做爲一個字符串給出,由四部分組成。第一個部分是必很多的,它必須是下面的幾個字符之一:
's' 或者 'S' 寫字符串;
'f' 或者 'F' 寫實數;
'i' 或者 'I' 寫整數。
這些字符能夠後接:
[?][m][.n]
? 指示字段的對齊方式
'<' 右對齊
'>' 左對齊
'|' 居中對齊
m 指示字符的大小
.n 對於實數,指示小數點的位數。對於整數,它是最小位數。對於字符串此位無心義。
當這個函數調用沒有給出格式字符串時,這個函數寫數字使用 %g 格式,寫字符串使用 %s 。
(未完待續)app