Lua C 扩展: 如何在新库上设置元表

经过多次尝试和数小时的谷歌搜索,我最终意识到 SOF 可能是解决这个问题的最佳场所。

我目前正在使用 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 进行索引。我还要指出的是,当我将其删除时,__index 元方法会被调用两次,显然它会被调用两次。

我的问题: 我该如何实现这一点?我正在尝试在表上设置元表并返回整个元表。 非常感谢任何帮助,因为我完全迷失了。谢谢。

点赞
用户2725326
用户2725326

你必须将元表设置到你的表中,通过将其推到堆栈的顶部,然后调用 lua_setmetatable

luaL_newlib(lua, lib);
lua_pushvalue(lua, -1);
lua_setmetatable(lua, -2);

调用 lua_pushvalue 将位置为 -1(堆栈顶部)的值再次推到堆栈上,复制它。然后,我们调用 lua_setmetatable(文档在这里 doc),将堆栈顶部的表弹出并将其设置为给定索引(-2,也就是我们通过 luaL_newlib 命令推入的 lib 表)的表的元表。

通过这样做并运行你的示例,我得到了以下结果:

local rpc = require "DiscordRPC"
print(rpc['a'])
-- 首先,调用 __index 函数,打印 'Was indexeda'
-- 然后打印 nil,因为键 'a' 没有值
rpc.initialize();
-- 打印 ran

如果您对此有更多问题,建议您阅读《Lua 编程入门》中关于用户数据和面向对象访问的章节。

2019-01-30 14:50:34