Lua1.1 Lua 的参考手册 (二)
转载出处:http://my.oschina.net/xhan/blog/310017
(接上篇)
--------------------------------------
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 。
(未完待续)