1. 程式人生 > >lua中的閉包概念的學習筆記

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