(接上篇)编程
--------------------------------------
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