標籤:

談一談Lua中的閉包

最近在學習Lua,一門很輕量級的語言,深感其簡潔與優雅,故將自己學習過程中的一些新的記錄如下。

在閱讀《Programming in Lua》一書中,第六章第一小節closure(閉包)有些費解,查閱了一些資料後,總結如下。

Functions in Lua are first-class values with proper lexical scoping.

—— Programming in Lua.

在Lua語言中,有兩個很有意思的特性:

  1. 所有的函數都是匿名函數。可以這樣理解,function實際上是佔據在某個內存位置中,函數名不過是對這一實體的引用(Reference)。如下例:
  2. function foo(x) return 2 * xend

    等價於:

    foo = function (x) return 2 * xend

    可以看到第二種寫法,實際上是定義了一個匿名函數(沒有名稱的函數),然後將這個函數賦給了foo這個變數。

    下面看另外一個例子:

    function func() return function () print("Hello World") endendlocal f1 = func()print(f1) -- 運行結果 function: 0x41dc6186f1() -- 運行結果 Hello World

    上述例子說明了,函數是同樣可以作為另外一個函數的返回值的。測試過程中,第一行返回了函數在內存中的地址,第二行運行了該函數。

  3. 被嵌套的函數可以訪問它外層的數據,為了說明這個問題,請看這個例子:

function func() local index = 0 local inner = function () print(index) index = index + 1 end inner() -- 結果:0 inner() -- 結果:1 print(index) -- 結果:2endfunc()

上一個例子說明了,外層函數func()中的局部數據index是可以被內層函數inner()訪問和修改的,index也被稱作inner()的upvalue。

結合上述兩點,我們可以得到更多有意思的結論,如這個例子:

function func() local index = 0 print("Hello") return function () print(index) index = index + 1 endendlocal inner = func()print(inner) -- 結果: function: 0037BE88inner() -- 結果: 0inner() -- 結果: 1local othre = func()other() -- 結果: 0other() -- 結果: 1

由此可以看出函數的局部變數是可以保存在函數內部的,通過調用該函數內嵌的函數可以獲取並修改局部變數的值,該函數的局部變數(upvalue)和內嵌函數的組合使用,形成了閉包,這看起來與C++中類的成員變數有些類似。函數具有閉包的功能後,不必再擔心其局部變數沒辦法保存了,這一點對程序員的影響是很大的。

還有另一個例子:

function func() local index = 0 return function () index = index + 1 return index endendlocal inner = func()print(inner()) -- 結果: 1print(inner()) -- 結果: 2

推薦閱讀:

Lua 有哪些優點,適用於哪些場景?
陰陽師肝不動了,試試Lua吧
為什麼很多編程語言用 end 作為區塊結束符,而放棄花括弧?
維基百科中模板和模塊有什麼區別?
Lua程序逆向之Luac位元組碼與反彙編

TAG:Lua | Lua編程 |