2010-08-10 109 views
4

我在C应用程序中使用Lua,我有两个表。我想创建一个第三个表,虽然它是空的,但会从我的前两个表中索引值。我在Lua中编写了以下简单示例 -Lua C API和metatable函数

a = { one="1", two="2" } 
b = { three="3", four="4" } 

meta = { __index = function(t,k) 
    if a[k] == nil then return b[k] 
    else return a[k] end 
end } 

c = {} 
setmetatable(c, meta) 

print(c.one) -- prints "1" 
print(c.four) -- prints "4" 

我的问题是,从C API执行此操作的最有效方法是什么?我已经能够通过创建一个新表来实现这一点,将上面的Lua代码块推到该表上,然后调用setmetatable(),但这看起来并不理想。有没有更好的办法?

+3

顺便说一句,你的__index函数简化为'返回a [k]或b [k]'。 – 2010-08-10 16:31:31

+5

@Judge Maygarden:不在这种情况下[k]可能是假的 – daurnimator 2010-08-11 06:13:52

+0

@daurnimator真的。接得好。 – 2010-08-11 13:53:30

回答

11
#include <stdio.h> 
#include "lua.h" 

/* __index metamethod for the 'c' table (stack: 1 = table 'c', 2 = desired index) */ 
static int 
cindex(lua_State *L) 
{ 
    /* try the global 'a' table */ 
    lua_getglobal(L, "a"); 
    lua_pushvalue(L, 2); 
    lua_gettable(L, -2); 
    if (!lua_isnil(L, -1)) 
     return 1; 

    /* try the global 'b' table */ 
    lua_getglobal(L, "b"); 
    lua_pushvalue(L, 2); 
    lua_gettable(L, -2); 
    if (!lua_isnil(L, -1)) 
     return 1; 

    /* return nil */ 
    return 0; 
} 

int 
main(int argc, char **argv) 
{ 
    lua_State *L; 

    L = (lua_State *) luaL_newstate(); 
    luaL_openlibs(L); 

    /* create the global 'a' table */ 
    lua_createtable(L, 0, 2); 
    lua_pushstring(L, "1"); 
    lua_setfield(L, -2, "one"); 
    lua_pushstring(L, "2"); 
    lua_setfield(L, -2, "two"); 
    lua_setglobal(L, "a"); 

    /* create the global 'b' table */ 
    lua_createtable(L, 0, 2); 
    lua_pushstring(L, "3"); 
    lua_setfield(L, -2, "three"); 
    lua_pushstring(L, "4"); 
    lua_setfield(L, -2, "four"); 
    lua_setglobal(L, "b"); 

    /* create the global 'c' table and use a C function as the __index metamethod */ 
    lua_createtable(L, 0, 0); 
    lua_createtable(L, 0, 1); 
    lua_pushcfunction(L, cindex); 
    lua_setfield(L, -2, "__index"); 
    lua_setmetatable(L, -2); 
    lua_setglobal(L, "c"); 

    /* run the test script */ 
    luaL_loadstring(L, "print(c.one)\nprint(c.four)"); 
    if (0 != lua_pcall(L, 0, 0, 0)) { 
     puts(lua_tostring(L, -1)); 
     return 1; 
    } 

    return 0; 
} 
2

您是否可以修改b的metatable?如果是这样,这是更有效的:

a = { one="1", two="2" } 
b = { three="3", four="4" } 

setmetatable(b, { __index = a }) 

-- setmetatable(x, m) returns x, so you can do this: 
c = setmetatable({}, { __index = b}) -- meta is here, too 

print(c.one) -- prints "1" 
print(c.four) -- prints "4" 

__index指向一个表,它比当它指向一个功能更高效;我在某处读到它相当于C中的3个间接指针。所以在最坏的情况下(c.one)总共有6个间接指针。