2010-08-10 2 views
4

루아를 C 응용 프로그램 내에서 사용하고 있는데 두 개의 테이블이 있습니다. 비어있는 동안 첫 번째 두 테이블의 값을 인덱싱하는 세 번째 테이블을 만들고 싶습니다.루아 C API와 메타 함수들

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

BTW, 귀하의 __index 함수는'a [k] 또는 b [k]'를 반환합니다. –

+5

@ Judge Maygarden : a [k]가 거짓일 수는 없습니다. – daurnimator

+0

@daurnimator True. 좋은 캐치. –

답변

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의 메타 테이블을 수정할 수 있습니까? 그렇다면,이 더 효율적입니다 :

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 개의 우회가 있습니다.