我是Lua的新手
我有一个注册到Lua的C函数,如下所示:
call(obj, "func", param0, param1)
在call()
:
obj
(以及所有参数)都是固定包装类型(类似于boost::any
)因此,我们不能使用常规的Lua绑定工具(luabind,luabridge等)进行简单的类成员注册
以下是问题:
我们如何简化Lua调用:
obj.func(param0, param1)
或
obj:func(param0, param1)
感谢。
答案 0 :(得分:2)
您必须在您创建的每个obj
上设置metatable(假设它是您控制下的userdata并且没有metatable)并覆盖__index
metamethod:
local cache = { }
debug.setmetatable(obj, {
__index = function (obj, k)
return function (obj, ...) -- or (...) for [non-canonical] .-syntax
return call(obj, k, ...)
end
-- malloc-optimized version --
local f = cache[k] or function (obj, ...) return call(obj, k, ...) end
cache[k] = f
return f
end,
__metatable = "whatever",
})
f = obj.func
f(obj, param0, param1) --> call(obj, 'func', param0, param1)
obj:func(param0, param1) --> the same via syntactic sugar
如果obj
已经有了metatable,那么必须以类似的方式修改metatable。
同样可以通过C界面完成,因此您可以将obj
创建与__index
设置相结合。
C方面的更新:
如果创建函数在外部库中,那么除了捕获所有对象外观点(在作为参数传递的表中返回值和值)并且如上所述换行之外,你没有其他选项。
如果创建功能在您的控制之下,您可以看到类似的内容:
ud = lua_newuserdata(L, sizeof(object));
*ud = object;
// this part is missing if objects have no metatable at all
luaL_getmetatable(L, tname); // or 'if (luaL_newmetatable(L, tname)) { ... }'
lua_setmetatable(L, -2);
return 1;
您必须在创建metatable的位置添加__index元方法:
...代码中的某个地方,也许就在*ud = object
行...
if (luaL_newmetatable(L, tname)) {
... original metatable setup ...
int res = luaL_loadstring(L,
"return function (obj, k)\n"
" return function (obj, ...)\n"
" return call(obj, k, ...)\n"
" end\n"
"end\n");
assert(res == 0);
lua_call(L, 0, 1);
lua_setfield(L, -2, "__index");
}
如果您的userdata根本没有metatable,则必须创建并设置它。
如果你想摆脱全局符号call
,那么将它的C实现作为参数传递给luaL_loadstring'ed chunk:
luaL_loadstring(L, "local call = ...\n return function (obj, k)\n" ...);
lua_pushcfunction(L, l_call);
lua_call(L, 1, 1); // instead of (0, 1)
然后call
将被本地化为闭包。