本站文章均爲Jensen抹茶喵原創,轉載務必在明顯處註明:
轉載自【博客園】 原文連接:http://www.cnblogs.com/JensenCat/p/5112420.htmlhtml
1.什麼是閉包java
支持閉包特性一般須要一個嵌套函數,經過執行嵌套函數來改變所在父函數的局部變量狀態,父函數保存調用上下文狀態,而嵌套函數負責修改狀態的改變.(簡單來講就是得支持函數嵌套)api
下面就是一個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中能夠經過某個方法來獲取這個方法的局部變量,而後經過這個方法內的方法來讀取想要的變量值。lua
function func3() local num3 = 44 function func4() return num3 end return func4 end local func = func3(); print(func())
解釋:spa
1.在外部沒法獲取到func3內部的局部變量,可是func3內部的局部方法func4卻能夠獲取到,所以返回一個func4的引用 ,這樣在外部經過這個func4就能夠獲取到func3的內部變量。code
2.雖然是繞了一個圈子,可是在方法外部卻經過這樣一個手段獲取到了內部的值。而這個方法內的局部方法func4就叫作閉包,按照不少書上的概念,這個方法搭建了方法內部與方法外部的橋樑,使得在外部也能夠任意的獲取到方法內部的資源。htm
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來實現狀態機了