2010-08-10 73 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個間接指針。