lua中的閉包概念的學習筆記
1、閉包的由來:
個人理解,lua中之所以出現閉包的概念,完全是因為lua中允許函式的巢狀定義,並且在內嵌函式中使用了外包函式中定義的區域性變數,例如c、c#就不允許函式的巢狀定義(但是允許函式的巢狀呼叫)
以下是函式巢狀定義的一個例子:
1 function fun1(n) 2 local function fun2() 3 print(n) 4 end 5 6 return fun2 7 end
fun1叫做fun2的外包函式,fun2叫做fun1的內嵌函式,並且這中內嵌與外包關係是允許傳遞的。什麼意思呢?就是fun1的外包函式也是fun2的外包函式,fun2的內嵌函式也是fun1的內嵌函式。
我們都知道,函式中定義的區域性變數的生命週期就是在函式執行完後就結束了。假如現在有如下邏輯:
1 fun3 = fun1(2048) 2 fun3()
執行結果如下:
從執行結果上看,2048的生命週期好像不是在fun1執行完就結束的,看著像是在fun2執行完才結束的。事實是這樣的嗎?
當fun3被呼叫時,其函式體訪問了外部的區域性變數n。當呼叫fun2函式時,建立fun2的fun1函式已經返回了,即執行結束,那麼外部區域性變數的生命週期也就結束了,這個時候在fun2中繼續如何訪問區域性變數 n 呢?
閉包就是為了解決這個問題出現的。
其實不同的語言,對該問題有不同的處理方式,例如c、c#直接就不允許函式的巢狀定義,從根源避免問題的產生;python則是通過限定作用域來解決該問題。
2、編譯時: lua編譯一個函式時,會為它生成一個原型(prototype) --- 包括 函式體對應的虛擬機器指令、函式執行用到的常量、一些除錯資訊。
執行時: 每當lua執行一個形如function...end 這樣的表示式時,它就會建立一個新的資料物件,其中包含了相應函式原型的引用、環境(environment,用來查詢全域性變數的表)的引用以及一個由所有upvalue引用組成的陣列,而這個資料物件就稱為閉包。
即函式是編譯期概念,是靜態的,而閉包是執行期概念,是動態的。
3、詞法定界:當一個函式內巢狀另一個函式的時候,內函式可以訪問外部函式的區域性變數,這種特徵叫做詞法定界。
閉包的產生:呼叫了某種型別的外包函式產生的一個例項函式(類似上面的程式碼示例),這個外包函式滿足,它的內嵌函式訪問了在它中定義的區域性變數。
閉包組成:外部函式+外部函式建立的區域性變數+內部函式(閉包函式)
參考:https://blog.csdn.net/maximuszhou/article/details/44280109
https://www.cnblogs.com/zzy-frisrtblog/p/5864209.html
http://blog.chinaunix.net/uid-52437-id-2108789.html