本站文章均为Jensen抹茶喵原创,转载务必在明显处注明:
转载自【博客园】 原文链接:http://www.cnblogs.com/JensenCat/p/5112420.html
1.什么是闭包
支持闭包特性通常需要一个嵌套函数,通过执行嵌套函数来改变所在父函数的局部变量状态,父函数保存调用上下文状态,而嵌套函数负责修改状态的改变.(简单来说就是得支持函数嵌套)
下面就是一个Lua闭包:
function counter() local cnt = 0 --返回匿名函数也是可以的 local Closure = function() cnt=cnt+1 print("print:"..cnt) end return Closure end function main() local Closure = counter() Closure() --print:1 Closure() --print:2 Closure() --print:3 local newCounter = counter() newCounter() --print:1 newCounter() --print:2 Closure() --print:4 --可以看出他们引用的计数对象是不一样的,更像是同一个类的2个不同的对象 end
2.闭包的作用
下面是一个java的类,getName方法获取到了类对象的私有成员变量
class Person { private String name; public String getName() { return name; } }
通过上面的方式可以获取到一个类内部的私有属性,同样的,在lua中可以通过某个方法来获取这个方法的局部变量,然后通过这个方法内的方法来读取想要的变量值。
function func3() local num3 = 44 function func4() return num3 end return func4 end local func = func3(); print(func())
解释:
1.在外部无法获取到func3内部的局部变量,但是func3内部的局部方法func4却可以获取到,因此返回一个func4的引用 ,这样在外部通过这个func4就可以获取到func3的内部变量。
2.虽然是绕了一个圈子,但是在方法外部却通过这样一个手段获取到了内部的值。而这个方法内的局部方法func4就叫做闭包,按照很多书上的概念,这个方法搭建了方法内部与方法外部的桥梁,使得在外部也可以任意的获取到方法内部的资源。
3.但是闭包会造成变量在内存中持久占用,因此会有一定的性能问题,最好不要轻易使用,即便使用也要在恰当的实际进行释放。
3.游戏开发中的应用
--以下用cocos2dx中的Lua来举例... --2dx通过tolua++把类方法导出 --举例api --按钮响应回调函数格式为: --luaFunc(event) --event为触摸按下,触摸移动,触摸离开等事件 --lua中的API为: --UIButton::addListenHandler(luaFunc) --实际需求是我按钮按下时,我需要改变按钮自身的纹理...此时回调中却没有按钮本身的对象(sender),怎么办呢? --利用闭包就轻松解决了 --下面是LUA实战例子:一个testUI的页面类 local testUI = testUI or {} local testUI:onBtnClick(sender,event) --可获取的参数有:隐藏的self,btn,event end function testUI:initButton() local btn = UIButton:create() --重点来了 btn:addListenHandler( function(event) --使用闭包把self,btn都传进去了.... self:onBtnClick(btn,event) end ) end return testUI
4.lua函数递归以及尾调用消除
1)递归示例:
--反面递归例子(递归必须在初始化以后才能调用) local func = function(n) if n > 0 then return func(n - 1) --此处调用错误 end --正确例子1 local func func = function(n) if n > 0 then return func(n - 1) --此处调用错误 end --正确例子2(此处函数展开后解释为例子1的代码再执行) function func(n) if n > 0 then return func(n - 1) --此处调用错误 end --如果是两个函数嵌套递归(超前递归,必须先声明) local g local f --这里不能加local..不然等于声明了多一个局部变量了,递归的对象就不对了 function g() f() end --这里不能加local..不然等于声明了多一个局部变量了,递归的对象就不对了 function f() g() end
2)尾调用消除(递归的时候如果返回的函数是最后的执行...则不损耗栈空间,相当于GOTO语句)
--尾调用消除 function g() return a,b end --正确例子 function f() return g() --正确的尾调用消除 end --错误例子1 function f(x) return g() + 1 --最后执行的是加法 end --错误例子2 function f(x) return (g()) --最后执行的是强制返回1个值 end --错误例子3 function f(x) return x or g() end
总结:由于LUA尾递归调用这个性质,我们可以用GOTO来实现状态机了
请发表评论