Lua閉包使用心得

本站文章均爲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來實現狀態機了

相關文章
相關標籤/搜索