前言: 本篇文章是我啃书加看博客搓出来的,我会尽可能讲解的通俗易懂,如果文章中某个地方是你认为不符合规范的,欢迎指出和讨论。
概念:当一个函数内部嵌套另一个函数定义时,内部定义的函数体可以访问外部函数的局部变量;简单的说闭包是一个函数加上它可以正确访问的upvalues(外部函数的局部变量)。
如果你没看懂上面的概念的话先不用深究,继续往下看,看完这篇文章后再回来理解这句话。
想要理解上面的那句概念,得先搞懂几个小概念:内部定义的函数体、外部函数的局部变量。
function test()
local i=0; --外部函数的局部变量 (也就是upvalue)
return function() --内部定义的函数体
i=i+1;
print(i);
end
end
c1=test();
c1();
在上面这个代码块中,test方法的返回值是一个函数体,在这个函数体内部调用了test方法的局部变量i,这种现象就称为闭包。c1中存储的方法,就是test方法内的闭包(不知道这样描述对不对,知道我说的啥意思,理解就行)。
我的理解版概念:当一个函数的返回值是一个函数体,并且这个函数体内部调用了这个函数内部声明的变量或者这个函数的参数时,那这个函数的返回值就是一个闭包。
运行结果:
>lua -e "io.stdout:setvbuf 'no'" "6.16.lua"
1
>Exit code: 0
c1中存储的是test方法的返回值,test方法已经执行结束,但是它的返回值c1里面还调用了test方法的局部变量i的值,在lua的闭包机制中,这个变量会在闭包中进行存储,并且会记录这个变量运行之后的值,也就是在调用时,这个变量存储的是上一次调用执行完之后的值。
function test()
local i=0
return function()
i=i+1;
print (i);
end
end
c1=test();
c1(); --第一次执行时i的值是0,执行结束之后i的值是1;
c1(); --所以第二次执行这个方法时,i的值是1,执行结束之后i的值是2;...以此类推;
c1();
c1();
c1();
执行结果:
>lua -e "io.stdout:setvbuf 'no'" "6.16.lua"
1
2
3
4
5
>Exit code: 0
使用闭包来实现迭代器
- 也就是遍历集合中的元素,每一次执行都会调用集合中的下一个元素。(迭代器的具体概念可以查阅相关资料,这里举一个简单的例子)
list_1={
1,2.3,4,5,6,7,8};
function forList(list)
local n=1;
local maxN=table.getn(list);
return function() --这是一个闭包
if n<=maxN then print(list[n]) end
n=n+1; --每次调用都会将n的值+1也就是每次调用都会输出集合中的下一个元素
end
end
lis=forList(list_1);
lis()
lis()
lis()
lis()
lis()
执行结果:
>lua -e "io.stdout:setvbuf 'no'" "6.16.lua"
1
2.3
4
5
6
>Exit code: 0
总结:关键是闭包中存在upvalue存储上一次执行后的结果的机制,才能每次调用时都是输出集合中的下一个元素。