概念
1.lua中的闭包(closure)由一个函数,以及函数会用到的变量(upvalue)组成。
2.变量没有说是全局或者局部,因为这里的变量既不是全局,也不是局部的。
3.闭包的使用更像是创建了一个临时的环境,这个临时环境中,变量可供这个环境内所有函数调用,但是离开这个闭包环境,这些变量是不可访问的。
用处
1.闭包可以利用内嵌的私有函数,很巧妙的实现一些简单的面向对象的的逻辑,比如我们要判断一个生成一个圆的判断对象,
传统做法:
function in_circle(x,y,r,check_x,check_y)
return (check_x -x)^2 + (check_y-y)^2 <=r^2;
end
这样写是可以的,但是如果持续判断一连串的点是否在同一个圆内的时候就显得很累赘,并且要求的参数过于多,理解起来也相对麻烦,如果是面向对象的写法可以写成下面这样:
local Circle = class("Circle")
function Circle:ctor(x,y,r)
self.x = x
self.y = y
self.r = r
end
function Circle:in_circle(check_x,check_y)
return (check_x -self.x)^2 + (check_y-self.y)^2 <=self.r^2;
end
使用传统面向对象的方法之后,我们就可以创建一个指定参数的圆,然后每次去调用圆的in_circle函数就可以了,这样将圆对象化,让这个对象帮我们做判断,参数和过程都极大的简化。但是lua本身就属于精简的语言,我们真的有必要为了一些简单的逻辑,去创建一个类吗?答案是不必的,闭包可以很巧妙的帮我们实现这个问题。下面看一下闭包的实现:
function circle(x,y,r)
return function (check_x,check_y)
return (check_x -x)^2 + (check_y-y)^2 <=r^2;
end
end
这样,闭包就为我们创建了一个比较抽象但是又是独立的运行环境,其中的upvalue就是x,y,r三个参数,我们指定这三个参数,返回的就是一个包含了这三个参数的闭包函数,我们要做的就是使用这个闭包函数来满足我们的需求
local c1 = circle(1,1,4)
local c2 = circle(3,3,1)
print(c1(1,1)) -->true
print(c2(1,1)) -->false
print(c2(3,3.5)) -->true
这样是不是极大的简化了代码,但是又让编程过程符合面向对象思想
安全沙盒模式下,运行网络代码进行文件读取
1.我们可能会面临一个问题,从网络上down了一份代码在本地运行,但是我们不能保证他们是安全的,比如在文件读取的时候,我们不希望本地的敏感文件被读取。
2.创建一个局部环境,利用闭包修改公用的文件读取
do
local old_open = io.open
local access_ok = function (filename)
return check_something
end
io.open = function(filename)
if(access_ok(filename)) then
return old_open(filename)
else
return nil, "file_denied"
end
end
--在这个do---end范围内,down下来的代码利用io.open读取文件时都必须经过检验,
--通过检验的文件才能被读取,这样可以在不知道代码,并且不改变文件的情况下做到一些安全处理
end
总结
闭包时很好用的技巧,但是要注意不能滥用,尤其时存在大量的upvalue的情况下,因为程序栈会保存这些信息,在闭包函数没有被放弃之前,这些值会一直保留在内存中。当然也不必惧怕使用,因为闭包确实会给我们的编程带来一些很巧妙的构思