lua的閉包包括CClosure和FClosure兩種類型。下面的例子介紹如何在C中使用C創建的閉包函數,C中使用lua中創建的閉包函數,Lua中使用C中創建的閉包函數,Lua中使用Lua閉包就不贅述了。
C中通過lua_pushclosure創建閉包函數,在將閉包函數推到堆棧之前需要先把n個上值推到lua_state上。取用的時使用lua_upvalueindex(n)取的特定索引上的上值,更改的話可以使用lua_replace更改上值。例子中每次將上值+5,因此在lua中每次調用upvalue_test函數都會獲得正確的上值。lua中的closure想在C中進行upvalue的更改有一點麻煩,首先你需要獲取closure函數對象,使用lua_getupvalue將特定索引上的上值放到棧頂,可以使用lua_setupvalue重設上值。如果你的fclosure中沒有使用全局變量,那么其上值索引應該是按照local變量的聲明順序來的,但是一旦使用了全局變量,第一個上值必定是_ENV環境,也就是說你可以通過重新設置_ENV環境,修改全局的上值,這也是修改環境變量的一種方法。
C 文件:
#include <stdio.h> #include <string.h> #include <lua.h> #include <lauxlib.h> #include <lualib.h> #include <dlfcn.h> #include <math.h> static int mytest(lua_State *L) { //獲取上值 int upv = (int)lua_tonumber(L, lua_upvalueindex(1)); printf("%d\n", upv); upv += 5; lua_pushinteger(L, upv); lua_replace(L, lua_upvalueindex(1)); //獲取一般參數 printf("%d\n", (int)lua_tonumber(L,1)); return 0; } int main(void) { lua_State *L = luaL_newstate(); luaL_openlibs(L); //設置Cclosure函數的上值 lua_pushinteger(L,10); lua_pushinteger(L,11); lua_pushcclosure(L,mytest,2); lua_setglobal(L,"upvalue_test"); luaL_dofile(L, "./luatest.lua"); //獲取fclosure上值的名稱(臨時值, 不帶env) lua_getglobal(L, "l_counter"); const char *name = lua_getupvalue(L, -1, 1); printf("%s\n", name); //設置fclosure上值 lua_getglobal(L, "l_counter"); lua_pushinteger(L,1000); name = lua_setupvalue(L, -2, 1); printf("%s\n", name); lua_getglobal(L,"ltest"); lua_pcall(L,0,0,0); lua_getglobal(L,"ltest"); lua_pcall(L,0,0,0); //獲取fclosure的上值(帶env) lua_getglobal(L, "g_counter"); lua_getupvalue(L, -1, 1); //通過settable重新設置env中對應的值 lua_pushstring(L, "gloval_upvalue"); lua_pushinteger(L,10000); lua_settable(L,-3); lua_pushstring(L, "gloval_upvalue1"); lua_pushinteger(L,20000); lua_settable(L,-3); lua_getglobal(L,"gtest"); lua_pcall(L,0,0,0); lua_close(L); return 0; }
Lua 文件
gloval_upvalue = 10 gloval_upvalue1 = 20 local local_upvalue = 100 function l_counter() return function () local_upvalue = local_upvalue + 1 return local_upvalue end end function g_counter() return function () gloval_upvalue = gloval_upvalue + 1 return gloval_upvalue,gloval_upvalue1 end end g_testf = g_counter() l_testf = l_counter() function gtest() print(g_testf()) end function ltest() print(l_testf()) end upvalue_test(1,2,3) upvalue_test(4,5,6)