關於lua的閉包(Closure)和Upvalue
upvalue:嵌套函數的外部函數的局部變量
function func(a) <== 這個函數返回值是一個函數
return function ()
a = a + 1 <== 這裏可以訪問外部函數func的局部變量a,這個變量a就是upvalue
return a
end
end
func返回一個匿名函數,可用變量接取之。該匿名函數有一個upvalue a(有點像C函數的static變量),初值爲首次調用func時的參數
閉包:一個匿名函數加上其可訪問的upvalue
c = func(1) <== c現在指向一個擁有upvalue a = 1的匿名函數,c也被稱作一個閉包
c() <== 返回2
c() <== 返回3
c2 = func(1) <== c2現在指向另外一個擁有upvalue a = 1的匿名函數,c2也被稱作一個閉包
c2() <== 返回2
下面是示例代碼:
int generatecclosure(lua_State *L) /* 閉包產生器 */
{
lua_pushnumber(L, 0); /* 壓入第一個upvalue */
lua_pushnumber(L, 0); /* 壓入第二個upvalue */
lua_pushcclosure(L, cclosure, 2); /* 壓入閉包的同時也把upvalue置入該閉包的upvalue表 */
return 1; /* 返回閉包 */
}
int cclosure(lua_State *L)
{
double upval1, upval2;
upval1 = lua_tonumber(L, lua_upvalueindex(1)); /* 注意upvalue索引1,2是閉包依賴的,不會和其他的閉包中的索引衝突 */
upval2 = lua_tonumber(L, lua_upvalueindex(2));
upval1++; upval2++;
lua_pushnumber(L, upval1); lua_replace(L, lua_upvalueindex(1));/* 更新upvalue1 */
lua_pushnumber(L, upval2); lua_replace(L, lua_upvalueindex(2));/* 更新upvalue2 */
lua_pushnumber(L, upval1 + upval2);
return 1;
}
int generatecclosure2(lua_State *L)
{
lua_pushnumber(L, 10);
lua_pushnumber(L, 10);
lua_pushcclosure(L, cclosure2, 2);
return 1;
}
int cclosure2(lua_State *L)
{
double upval1, upval2;
upval1 = lua_tonumber(L, lua_upvalueindex(1));
upval2 = lua_tonumber(L, lua_upvalueindex(2));
upval1++; upval2++;
lua_pushnumber(L, upval1); lua_replace(L, lua_upvalueindex(1));
lua_pushnumber(L, upval2); lua_replace(L, lua_upvalueindex(2));
lua_pushnumber(L, upval1 + upval2);
return 1;
}
然後向lua虛擬機註冊一下全局函數:
lua_register(L, "generatecclosure", generatecclosure);
lua_register(L, "generatecclosure2", generatecclosure2);
最後執行main.lua:
c = generatecclosure()
c2 = generatecclosure2()
print(c()) -- 2
print(c()) -- 4
print(c2()) -- 22
print(c2()) -- 24