文档章节

Lua1.1 Lua 的参考手册 (二)

晓寒
 晓寒
发布于 2014/09/04 13:13
字数 3603
阅读 194
收藏 3

(接上篇)

--------------------------------------
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 。

(未完待续)

© 著作权归作者所有

晓寒
粉丝 35
博文 119
码字总数 133745
作品 0
海淀
私信 提问
Lua1.1 Lua 的参考手册 (一)

说明: 这个文档是 Lua1.1 的 doc 目录里的 manual.ps 文件。 原文版权归原作者所有,这篇翻译只是作为学习之用。如果翻译有不当之处,请参考原文。 -------------------以下是正文---------...

晓寒
2014/09/04
195
0
Lua1.1 Lua 的参考手册 (三)

(接上篇) -------------------------------------- 7 一些例子 -------------------------------------- 本段给出一些显示 Lua 特性的例子。它并不打算覆盖完整的语言,只是显示一有趣的使...

晓寒
2014/09/04
201
0
Lua1.1 公开发布的第一版

Lua1.1 是官方公开发布的第一版,是事实上的第一版 ,也是最早发布的一版。 代码从这里 www.lua.org/ftp/lua-1.1.tar.gz 下载,事实上在 www.lua.org/versions.html 页面,有所有的可以下下载...

晓寒
2014/09/02
329
1
Lua1.1 Lua 的设计和实现 (一)

说明: 这个文档是 Lua1.1 的 doc 目录里的 lua.ps 文件。 同时这个文档可以这里找到:http://www.lua.org/semish94.html 原文版权归原作者所有,这篇翻译只是作为学习之用。如果翻译有不当之...

晓寒
2014/09/03
394
0
Lua1.1 Lua 的设计和实现 (二)

(接上篇) -------------------------------------- 实现 -------------------------------------- 扩展语言总是由应用程序以某种方式解释执行的。简单的扩展语言可以直接从源代码进行解释执...

晓寒
2014/09/03
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

Redis缓存NoSQL

redis的应用场景有哪些 1、会话缓存(最常用) 2、消息队列,比如支付 3、活动排行榜或计数 4、发布、订阅消息(消息通知) 5、商品列表、评论列表等

BobwithB
17分钟前
3
0
「绘画技巧」一分钟画出动漫人物的喜怒哀乐中“喜”的各种表情

「绘画技巧」一分钟画出动漫人物的喜怒哀乐中“喜”的各种表情 表情拥有着可以凸显动漫人物情绪和主张的魔力,表情渲染整个环境。那么今天来和大家一起分享自己整理收集动漫人物喜怒哀乐中的...

知北
20分钟前
4
0
从流中的三种求和方式谈起

//使用reduce()方法int reduce = Arrays.asList(ins).stream().reduce(0, Integer::sum);//Collectors类的工厂方法,收集器int collect1 = Arrays.asList(ins).stream().collect(Colle......

我的眼里只有眼屎
21分钟前
2
0
File类的使用(文件与文件夹,获取,判断存在,删除,)

//File类的使用 public static void main(String[] args) throws IOException, ClassNotFoundException { //test3();// File f = new File("E:\\资料\\第二阶段\\d......

zhengzhixiang
25分钟前
2
0
58到家MySQL军规升级版

转载 2018-03-30 58到家DBA 架构师之路 一、基础规范 表存储引擎必须使用InnoDB 表字符集默认使用utf8,必要时候使用utf8mb4 解读: 通用,无乱码风险,汉字3字节,英文1字节 utf8...

xiaolyuh
32分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部