Lua userdata数组访问和方法
发布时间:2020-12-14 21:43:36 所属栏目:大数据 来源:网络整理
导读:我用C语言编写了一个用于Lua的userdata类型.它有一些数组类型属性和各种方法.现在,如果你是这种类型,我使用你:set(k,v)resp. u:获取(k)访问数据,例如u:sort()作为方法.为此,我将__index设置为包含这些方法的表.现在,如果我想使用u [k] = v或u [k]访问数据
我用C语言编写了一个用于Lua的userdata类型.它有一些数组类型属性和各种方法.现在,如果你是这种类型,我使用你:set(k,v)resp. u:获取(k)访问数据,例如u:sort()作为方法.为此,我将__index设置为包含这些方法的表.现在,如果我想使用u [k] = v或u [k]访问数据,我需要设置__newindex和__index来设置resp get.但是其他方法再也无法访问了……
在C中处理这个问题的最佳方法是什么?我猜我需要在C中编写一个函数来注册为__index并以某种方式处理它.也许检查密钥是否属于Lua方法表,如果是,则调用它. 任何帮助/提示将不胜感激.我没有找到这样的例子,虽然这对我来说似乎是很自然的事情. 编辑:在Lua中添加了我的C版解决方案,在下面的答案中发布.这或多或少都是直接翻译,所以所有功劳都归功于@ gilles-gregoire. 以下C函数注册为__index元方法. static int permL_index(lua_State *L) { struct perm **pp = luaL_checkudata(L,1,PERM_MT); int i; luaL_getmetatable(L,PERM_MT); lua_pushvalue(L,2); lua_rawget(L,-2); if ( lua_isnil(L,-1) ) { /* found no method,so get value from userdata. */ i = luaL_checkint(L,2); luaL_argcheck(L,1 <= i && i <= (*pp)->n,2,"index out of range"); lua_pushinteger(L,(*pp)->v[i-1]); }; return 1; }; 这是执行此操作的代码, int luaopen_perm(lua_State *L) { luaL_newmetatable(L,PERM_MT); luaL_setfuncs(L,permL_methods,0); luaL_setfuncs(L,permL_functions,0); lua_pop(L,1); luaL_newlib(L,permL_functions); return 1; }; 其中permL_methods是 static const struct luaL_Reg permL_methods[] = { { "__index",permL_index },{ "__eq",permL_equal },{ "__tostring",permL_tostring },{ "__gc",permL_destroy },[...] { NULL,NULL } }; 和permL_functions是 static const struct luaL_Reg permL_functions[] = { { "inverse",permL_new_inverse },{ "product",permL_new_product },{ "composition",permL_new_composition },NULL } }; 解决方法
这看起来像一个可以用嵌套元表解决的问题.你需要一个metatable用于方法(比如你的sort()方法),第二个用于索引操作.第二个metatable实际上是metatable方法的metatable.
让我把它写成lua代码.你需要3个表: -- the userdata object. I'm using a table here,-- but it will work the same with a C userdata u = {} -- the "methods" metatable: mt = {sort = function() print('sorting...') end} -- the "operators" metatable: op_mt = {__index = function() print('get') end} 现在,棘手的部分就在这里:当你调用一个方法时,lua会首先查找你. -- first level metatable mt.__index = mt setmetatable(u,mt) -- second level metatable setmetatable(mt,op_mt) 你现在可以像这样使用你的: > u:sort() sorting... > = u[1] get nil 编辑:通过使用__index元方法的函数更好的解决方案 使用__index元方法的函数可能是正确的方法: u = {} mt = {sort = function() print('sorting...') end} setmetatable(u,mt) mt.__index = function(t,key) -- use rawget to avoid recursion local mt_val = rawget(mt,key) if mt_val ~=nil then return mt_val else print('this is a get on object',t) end end 用法: > print(u) table: 0x7fb1eb601c30 > u:sort() sorting... > = u[1] this is a get on object table: 0x7fb1eb601c30 nil > (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |