我正在用 C 编写一个用户数据类型,以便在 Lua 中使用。它有一些数组类型的属性和各种方法。现在如果你是这种类型,我使用u:set(k,v)
resp. u:get(k)
访问数据,例如u:sort()
作为方法。为此我设置了__index
到包含这些方法的表。现在如果我想使用访问数据u[k] = v
or u[k]
,我需要设置__newindex
and __index
to set
resp get
。但是其他方法就无法访问了...
在 C 中处理这个问题的最佳方法是什么?我猜我需要用 C 编写一个函数来注册__index
并以某种方式在那里处理它。也许检查 key 是否属于 Lua 方法表,如果是则调用它。
任何帮助/提示将不胜感激。我没有找到这样的例子,尽管(对我来说)这似乎是一件很自然的事情。
edit:在下面的答案中添加了我在 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;
};
where permL_methods
is
static const struct luaL_Reg permL_methods[] = {
{ "__index", permL_index },
{ "__eq", permL_equal },
{ "__tostring", permL_tostring },
{ "__gc", permL_destroy },
[...]
{ NULL, NULL }
};
and permL_functions
is
static const struct luaL_Reg permL_functions[] = {
{ "inverse", permL_new_inverse },
{ "product", permL_new_product },
{ "composition", permL_new_composition },
[...]
{ NULL, NULL }
};