您必须在您创建的每个obj 上设置一个元表(假设它是您控制的用户数据并且没有元表)并覆盖其中的__index 元方法:
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 已经有一个元表,则必须以类似的方式修改该元表。
同样可以通过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;
您必须在创建元表的位置添加 __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");
}
如果您的用户数据根本没有元表,则必须创建和设置它。
如果你想摆脱全局符号call,那么将其 C 实现作为参数传递给 luaL_loadstring'ed 块:
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 将被本地化到闭包中。