Lua Programing
UserData
通过lua的UserData可以存储C中创建的自定义类型,首先通过lua_newuserdata
创建一块内存,然后用自定义类型的指针指向这块内存,
然后我们就可以在C中操作自定义类型了。
upvalues
其他
luaL_error
1 2 3 4 5 6 7 8 9 |
|
引用
我们没办法使用C指针来指向一个lua对象,因此如果想在C代码中传递lua对象就只能使用lua给我们提供的引用系统。因此当我们在C代码中需要指向一个lua对象的时候,可以先给 这个lua对象创建一个引用,然后在C代码中保存这个引用就可以。这样就可以通过传递引用的方式来代替传递lua对象。lua中的引用本质上其实就是注册表中以数值为key,以lua对象 为value的字段。
int luaL_ref (lua_State *L, int t);
在t所在table中,创建一个引用,并将栈顶的元素进行引用关联,最终返回一个唯一的数值。接下来通过这个数值,我们就可以通过lua_rawgeti
获取到引用的对象了。
1 2 3 4 5 |
|
全局变量和环境
Lua5.3中没有全局变量,但是会通过全局环境(global environment,一个普通的表)来进行模拟,Lua加载代码运行的时候,会创建一个名为_ENV的upvale,这是一个普通的表 是在Lua虚拟机初始化的时候就被创建了,里面包含了各种标准库函数。在我们访问全局变量的时候, 实际上是在访问上值 _ENV 中的键值,lua编译器在编译的时候,其实就会给 所有的全局变量都会被重写成对_ENV表的字段访问。G其实就是_ENV中的一个字段。_G实际指向了_ENV。
1 2 3 4 |
|
函数
lua_call
lua_pcall
协程和线程
lua_State *lua_newthread (lua_State *L);
创建一个线程,然后放到栈顶,并且返回lua_State来表示这个新的线程。这个返回的新lua_State和原来的lua_State共享所有的全局对象,但是有自己独立的执行栈。
int lua_resume (lua_State *L, int narg);
启动或者恢复指定协程,需要将要运行的funcion、以及参数都放到堆栈中。如果这个协程运行结束没有任何错误就返回0,如果返回的是LUA_YIELD
,表明协程停止了,此时堆栈上
放着
Starts and resumes a coroutine in a given thread.
To start a coroutine, you first create a new thread (see lua_newthread); then you push onto its stack the main function plus any arguments; then you call lua_resume, with narg being the number of arguments. This call returns when the coroutine suspends or finishes its execution. When it returns, the stack contains all values passed to lua_yield, or all values returned by the body function. lua_resume returns LUA_YIELD if the coroutine yields, 0 if the coroutine finishes its execution without errors, or an error code in case of errors (see lua_pcall). In case of errors, the stack is not unwound, so you can use the debug API over it. The error message is on the top of the stack. To restart a coroutine, you put on its stack only the values to be passed as results from yield, and then call lua_resume.
lua_yeild
基本操作
lua_pushvfstring
luaL_where
lua_concat
luaL_typename
表和元表
registry 是lua的注册表(是一张只能被C代码访问的全局表),获取registry就和获取普通的表一样,可以像操作普通的表一样来操作registry表,只不过这个表的默认在栈中的位置是LUA_REGISTRYINDEX
(lua中定义了这个值为-10000),这个位置并不是真实存在的我们称之为伪索引。通过这个伪索引就可以获取到registry表,然后我们就可以像操作正常表一样的方式来操作registry表了。所有的C库代码都共享
同一个registry表,因此我们需要小心使用这个表,避免冲突。
不能用
lua_remove
和lua_insert
来操作registry表,因为registry并不是真实存在于堆栈中,而lua_remove
和lua_insert
要操作真实存在于堆栈中的值。 registry注册表中不能使用数值类型的键,因为lua语言将数值键用作引用系统了。
int luaL_newmetatable (lua_State *L, const char *tname)
创建一个元表,并放到registry中,内部其实就是通过lua_newtable
,创建了一个普通的表,然后通过lua_setfield
给registry注册表添加了一个key为tname,value为空table的字段。 并将其放在registry表,而普通的表是放在global中的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
void lua_gettable (lua_State *L, int index)
首先从index处获取到table,然后用栈顶的值作为表的key来获取其value,最后将获取到的value放到栈顶上。
1 2 3 4 5 6 |
|
void lua_setfield (lua_State *L, int index, const char *k)
通过index找到table,然后给这个table设置key为k,value为栈顶值。
1 2 3 |
|
__index
,value为元表自己的字段。
void luaL_register (lua_State *L, const char *libname, const luaL_Reg *l)
如果libname为空,就简单的将l所对应的一系列function注册到栈顶的table中,否则就先去注册表中
找key为_LOADED
的表(等同于package.load[libname]
)的libname字段,如果找到了就把function注册到libname对应的表中,否则就去
全局表中查找key为libname的表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
|
-
void lua_getglobal (lua_State *L, const char *name);
获取全局表中key为name的value值,也就是获取name全局变量 -
void lua_rawgeti (lua_State *L, int index, int n);
raw前缀的方法都是直接访问表本身,不会访问元表,这个方法用来访问index所在表中的key为n的值。
元方法
__index
当访问表中的元素不存在时,会间接的访问这个表对应元表中的__index
,如果元表中的__index
字段是一个表就访问这个表对应的字段,如果是一个函数的话就会调用这个函数
并且会把table和键作为参数传递给这个函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|