lua的闭包包括CClosure和FClosure两种类型。下面的例子介绍如何在C中使用C创建的闭包函数,C中使用lua中创建的闭包函数,Lua中使用C中创建的闭包函数,Lua中使用Lua闭包就不赘述了。
C中通过lua_pushclosure创建闭包函数,在将闭包函数推到堆栈之前需要先把n个上值推到lua_state上。取用的时使用lua_upvalueindexn)取的特定索引上的上值,更改的话可以使用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 mytestlua_State *L) { //获取上值 int upv = int)lua_tonumberL, lua_upvalueindex1)); printf"%d ", upv); upv += 5; lua_pushintegerL, upv); lua_replaceL, lua_upvalueindex1)); //获取一般参数 printf"%d ", int)lua_tonumberL,1)); return 0; } int mainvoid) { lua_State *L = luaL_newstate); luaL_openlibsL); //设置Cclosure函数的上值 lua_pushintegerL,10); lua_pushintegerL,11); lua_pushcclosureL,mytest,2); lua_setglobalL,"upvalue_test"); luaL_dofileL, "./luatest.lua"); //获取fclosure上值的名称临时值, 不带env) lua_getglobalL, "l_counter"); const char *name = lua_getupvalueL, -1, 1); printf"%s ", name); //设置fclosure上值 lua_getglobalL, "l_counter"); lua_pushintegerL,1000); name = lua_setupvalueL, -2, 1); printf"%s ", name); lua_getglobalL,"ltest"); lua_pcallL,0,0,0); lua_getglobalL,"ltest"); lua_pcallL,0,0,0); //获取fclosure的上值(带env) lua_getglobalL, "g_counter"); lua_getupvalueL, -1, 1); //通过settable重新设置env中对应的值 lua_pushstringL, "gloval_upvalue"); lua_pushintegerL,10000); lua_settableL,-3); lua_pushstringL, "gloval_upvalue1"); lua_pushintegerL,20000); lua_settableL,-3); lua_getglobalL,"gtest"); lua_pcallL,0,0,0); lua_closeL); 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) printg_testf)) end function ltest) printl_testf)) end upvalue_test1,2,3) upvalue_test4,5,6)