经过多次尝试和数小时的谷歌搜索,我终于意识到,软件可能是我解决这个问题的最佳场所。
我目前正在使用Lua C API创建一个扩展,这是一个共享库,您可以通过require
要求它使用它。我正在尝试执行与此非常类似的操作(对格式设置感到抱歉):
local data = {
something = "some"
}
local rpc = {}
function rpc.method()
print('ran')
end
function rpc.method2()
print('ran222')
end
local metatable = {}
metatable.__index = function(self, key)
return data[key]
end
setmetatable(rpc, metatable)
--------------------------------------------
rpc.method()
print(rpc['something'])
rpc.method2()
我当前的C代码如下所示:
static int lua_index(lua_State* lua) { //idk
std::cout << "Was indexed";
const char* a = luaL_checkstring(lua, 2);
std::cout << a << std::endl;
return 0;
}
static int lua_initialize(lua_State* lua) {
std::cout << "ran";
return 0;
}
static const struct luaL_Reg lib[] = {
{ "initialize", lua_initialize },
{"__index", lua_index},
{ NULL, NULL }
};
extern "C" int DISCORD_RPC_EXPORT luaopen_DiscordRPC(lua_State* lua) {
luaL_newlib(lua, lib);
lua_setmetatable(lua, 1);
return 1;
}
并以此为例:
local rpc = require "DiscordRPC"
print(rpc['a'])
rpc.initialize();
现在显然
rpc['a']
将返回nil(是的lua_index
实际上运行),因为lua_index
没有做任何事情,但是为什么我不能调用initialize
?很明显。上面写着:lua: main.lua:5: attempt to call a nil value (field 'initialize')
所以是零。如果我想删除lua_setmetatable(lua, 1);
函数,我可以调用该函数,但我不能按我的意愿对它进行索引。另外,我想指出,当我删除它时,DiscordRPC
元方法会被调用两次,显然它会。我的问题是:我怎样才能做到这一点?我试图在一个表上设置一个元表并返回整个元表。
非常感谢您的帮助,因为我完全迷路了。谢谢您。
最佳答案
必须将元表推到堆栈的顶部,然后调用lua_setmetatable
,才能将其设置为表。
luaL_newlib(lua, lib);
lua_pushvalue(lua, -1);
lua_setmetatable(lua, -2);
对
lua_pushvalue
的调用将再次将位置-1(堆栈顶部)上的值推送到堆栈,并复制它。然后,我们调用lua_setmetatable
(这里的文档doc)在堆栈顶部弹出一个表,并将其设置为给定索引中表的元表(-2,即lib,由luaL_newlib
命令推送)。通过这样做并运行您的示例,我得到了以下结果:
local rpc = require "DiscordRPC"
print(rpc['a'])
-- First, calls the __index function, printing
-- 'Was indexeda'
-- Then prints nil, since the key 'a' holds nothing
rpc.initialize();
-- Prints ran
如果您对此有更多的问题,我建议您阅读Lua书籍中关于Userdata and Object-Oriented Access编程的章节。
关于c - Lua C扩展:如何在新库上设置元表,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50845264/