Registry的使用
2018, Jan 30
介绍
Registry是一个位于伪索引LUA_REGISTRYINDEX处的全局table,确切的说,是一个常规table(也就是说,它没有元表) 伪索引和栈中的索引相似,不同的是,与伪索引关联的值并不在栈中。 Lua API中大多数接受索引作为参数的函数,也接受伪索引作为参数。
说明:
1.由于所有的C模块共享相同的registry,所以在挑选key的时候要特别小心,避免名称冲突。
使用字符串作为键值,在我们希望其他独立库访问我们数据的时候很有用。在选择字符串作为键的时候,建议不要使用通用名称,且不要在名称前加上库的名字。
不要使用数字作为注册表的键,因为Lua会为其引用系统保留数字键。这个系统是有辅助库中的一对函数组成,允许我们在不需要担心怎样创建键的前提下存储值。注意,只有在我们需要将引用存储到C结构中的Lua值中时候,才会考虑使用引用。
int ref = luaL_ref(L, LUA_REGISTRYINDEX);由于Lua没有提供任何指向table或function的指针类型,所以在需要访问这些对象的时候,可以使用引用,并将引用保存在C代码中。
2.要将与引用关联的值压入栈中,使用
lua_rawgeti(L, LUA_REGISTRYINDEX, ref)3.要释放引用及其关联的值,调用
lua_unref(L, LUA_REGISTRYINDEX)4.引用系统对nil值有特殊作用,当使用nil值调用lua_ref函数时,不会得到一个新引用,而是返回常量引用值LUA_REFNIL
luaL_unref(L, LUA_REGISTRYINDEX, LUA_REFNIL) /*不执行任何操作*/luaL_rawgeti(L, LUA_REGISTRYINDEX, LUA_REFNIL) /*向栈中压入nil值*/
使用方法
- 存储数据的标准步骤
- 定义一个字符串键,可以使用宏来定义
- 将地址和值分别入栈:使用lua_pushlightuserdata方法将键压入栈,然后将值压入栈
- 使用lua_settable方法将值保存到Registry中与键所对应地方(注:设置好之后,栈中的键与值会被弹出栈)
- 获取数据的标准步骤
- 将地址入栈
- 使用lua_gettable方法获取值
- 对值进行适当的转换
- 存储数据的快捷方法
- 先将值入栈
- 使用lua_rawsetp(L, LUA_REGISTRYINDEX, (void *)&key)将值保存到Registry table中(此时会将值从栈中弹出)
- 获取数据的快捷方法
- 使用lua_rawgetp(L, LUA_REGISTRYINDEX, (void *)&key)将获取到的值压入栈
- 对值进行适当的转换
例子
- 将地址定义成宏
#define TRANS_KEY ((char)'t') - 定义主要方法
static int myclibs_transliterate_arr(lua_State *L, int count) { size_t i, len; const char *str = luaL_checklstring(L, -2, &len); /* first argument should be a string */ luaL_checktype(L, -1, LUA_TTABLE); /* second argument should be a table */ // string buffer luaL_Buffer b; /* declare a luaL_Buffer variable */ luaL_buffinitsize(L, &b, len); /* initialize the Buffer */ for (i = 0; i < len; i++) { char ch[] = "x"; ch[0] = str[i]; lua_getfield(L, -1, ch); /* * lua_pushfstring(L, "%c", ch); /* push key */ * lua_rawget(L, -2); /* get table[key] */ */ int nil = lua_isnil(L, -1); if (nil) { lua_pop(L, 1); } else { const char *result = lua_tostring(L, -1); luaL_addvalue(&b); /* add result to buffer */ } } if (count == NULL) { lua_pushfstring(L, "%s\n", "calling with one argument"); } else { lua_pushfstring(L, "%s\n", "calling with two argument"); } luaL_pushresult(&b); /* push the result string onto the stack */ return 2; } -
保存数据的方法
/* set the transliteration table using registry */ MYCLIBS_API int myclibs_settrans(lua_State *L) { luaL_checktype(L, 1, LUA_TTABLE); /* first argument should be a table */ lua_pushlightuserdata(L, (void *)TRANS_KEY); /* push address */ lua_pushvalue(L, 1); /* push value */ lua_settable(L, LUA_REGISTRYINDEX); /* registry[&key] = table */ return 0; } -
获取数据的方法
/* get the transliteration table from the registry table */ MYCLIBS_API int myclibs_gettrans(lua_State *L) { lua_pushlightuserdata(L, (void *)TRANS_KEY); /* push address */ lua_gettable(L, LUA_REGISTRYINDEX); /* retrieve the table and push it onto the stack */ return 1; } -
定义给外部访问的函数
/* transliterate function */ MYCLIBS_API int myclibs_transliterate(lua_State *L) { // get and push table onto the stack int top = lua_gettop(L), nres = 0; //printf("%d\n", top); if (top == 1) { myclibs_gettrans(L); nres = myclibs_transliterate_arr(L, NULL); } else if (top == 2) { nres = myclibs_transliterate_arr(L, 2); } else { luaL_error(L, "bad argument size"); } return nres; }