1. 注册表
注册表是一个普通的table,我们可以将c函数中需要保存的状态都存储在注册表中,注册表是可以被多个c模块共享的。
由于注册表是一个普通table,我们同样可以在栈中对其进行操作,只是这个table的索引是由一个常量LUA_REGISTRYINDEX进行索引。
如何向注册表中存入一个值对:
lua_pushstring(L, "hello");
lua_setfield(L, LUA_REGISTRYINDEX, "key");
lua_getfield(L, LUA_REGISTRYINDEX, "key");
如何向注册表中存入数组元素:
lua_pushstring(L, "i am a student");
int key = luaL_ref(L, LUA_REGISTRYINDEX); // 由于注册表的数组中已经存放了部分元素,因此不能使用自定义的索引,必须使用系统提供的函数,就无须关心索引的问题
// 成功调用后,会返回一个当前元素的索引
lua_rawgeti(L, LUA_REGISTRYINDEX, key);
2. upvalue:
upvalue机制提供了一种能和c函数关联起来的数据,upvalue可以保存一个lua值,然后可以将任意多的upvalue和c函数关联。在调用该c函数的时候,我们就可以提取和该函数关联的所有upvalue,这种技术又叫c closure。。即时用同一函数创建的closure,它们之间都是相互独立,即它们都拥有自己的upvalue。
如何创建一个c closure:
static int counter (lua_State* L) { // 同样我们需要创建我们的函数,和普通c函数一样
int value = lua_tonumber(L, lua_upvalueindex(1)); // 提取第一个upvalue,这里有2个upvalue
value *= 2;
lua_pushnumber(L, value);
return 1;
}
int newcounter (lua_State* L) { // 用于创建c closure的函数
lua_pushnumber(L, 1); // 将所有upvalue值都压入栈,这些值大多数情况是lua调用时候传入的参数
lua_pushstring(L, "234");
lua_pushcclosure(L, &counter, 2); // 创建c closure,c函数是counter,最后一个参数是2,代表从栈顶开始向下的2个值都作为c closure的upvalue
return 1
}
实例:
c代码:
int t_tuple (lua_State* L) { int op = luaL_optint(L, 1, 0); if (op == 0) { int i; for (i = 1; !lua_isnone(L, lua_upvalueindex(i)); ++i) { lua_pushvalue(L, lua_upvalueindex(i)); } return i - 1; } else { luaL_argcheck(L, op > 0, 1, "index out of range"); if (lua_upvalueindex(op) == LUA_TNONE) return 0; else { lua_pushvalue(L, lua_upvalueindex(op)); return 1; } } } int t_new (lua_State* L) { int top = lua_gettop(L); lua_pushcclosure(L, t_tuple, top); return 1; }
lua代码:
local t = new (12, 2, "hello"); print(t()) print(t(2))