成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

關于LUA中閉包操作學習教程

移動開發 iOS
在運行時,每當Lua執行一個形如function...end 這樣的表達式時,它就會創建一個新的數據對象,其中包含了相應函數原型的引用、環境(environment,用來查找全局變量的表)的引用以及一個由所有upvalue引用組成的數組,而這個數據對象就稱為閉包。

關于LUA閉包操作學習教程是本文要介紹的內容,Lua中的函數是一階類型值(first-class value),定義函數就象創建普通類型值一樣(只不過函數類型值的數據主要是一條條指令而已),所以在函數體中仍然可以定義函數。假設函數f2定義在函數f1中,那么就稱f2為f1的內嵌(inner)函數,f1為f2的外包(enclosing)函數,外包和內嵌都具有傳遞性,即f2的內嵌必然是f1的內嵌,而f1的外包也一定是f2的外包。

內嵌函數可以訪問外包函數已經創建的所有局部變量,這種特性便是所謂的詞法定界(lexical scoping),而這些局部變量則稱為該內嵌函數的外部局部變量(external local variable)或者upvalue(這個詞多少會讓人產生誤解,因為upvalue實際指的是變量而不是值)。試看如下代碼:

  1. function f1(n) 

函數參數也是局部變量

  1.    local function f2()  
  2.       print(n) -- 引用外包函數的局部變量  
  3.    end  
  4.    return f2  
  5. end  
  6.  
  7. g1 = f1(1979)  
  8. g1() -- 打印出1979  
  9. g2 = f1(500)  
  10. g2() -- 打印出500 

當執行完g1 = f1(1979)后,局部變量n的生命本該結束,但因為它已經成了內嵌函數f2(它又被賦給了變量g1)的upvalue,所以它仍然能以某種形式繼續“存活”下來,從而令g1()打印出正確的值。

可為什么g2與g1的函數體一樣(都是f1的內嵌函數f2的函數體),但打印值不同?這就涉及到一個相當重要的概念――閉包(closure)。事實上,Lua編譯一個函數時,會為它生成一個原型(prototype),其中包含了函數體對應的虛擬機指令、函數用到的常量值(數,文本字符串等等)和一些調試信息。

在運行時,每當Lua執行一個形如function...end 這樣的表達式時,它就會創建一個新的數據對象,其中包含了相應函數原型的引用、環境(environment,用來查找全局變量的表)的引用以及一個由所有upvalue引用組成的數組,而這個數據對象就稱為閉包。由此可見,函數是編譯期概念,是靜態的,而閉包是運行期概念,是動態的。

g1和g2的值嚴格來說不是函數而是閉包,并且是兩個不相同的閉包,而每個閉包可以保有自己的upvalue值,所以g1和g2打印出的結果當然就不一樣了。雖然閉包和函數是本質不同的概念,但為了方便,且在不引起混淆的情況下,我們對它們不做區分。

使用upvalue很方便,但它們的語義也很微妙,需要引起注意。比如將f1函數改成:

  1. function f1(n)  
  2.    local function f2()  
  3.       print(n)  
  4.    end  
  5.    nn = n + 10  
  6.    return f2  
  7. end  
  8.  
  9. g1 = f1(1979)  
  10. g1() -- 打印出1989 

內嵌函數定義在n = n + 10這條語句之前,可為什么g1()打印出的卻是1989?upvalue實際是局部變量,而局部變量是保存在函數堆棧框架上(stack frame)的,所以只要upvalue還沒有離開自己的作用域,它就一直生存在函數堆棧上。這種情況下,閉包將通過指向堆棧上的upvalue的引用來訪問它們,一旦upvalue即將離開自己的作用域(這也意味著它馬上要從堆棧中消失),閉包就會為它分配空間并保存當前的值,以后便可通過指向新分配空間的引用來訪問該upvalue。

當執行到f1(1979)的n = n + 10時,閉包已經創建了,但是n并沒有離開作用域,所以閉包仍然引用堆棧上的n,當return f2完成時,n即將結束生命,此時閉包便將n(已經是1989了)復制到自己管理的空間中以便將來訪問。弄清楚了內部的秘密后,運行結果就不難解釋了。

upvalue還可以為閉包之間提供一種數據共享的機制。試看下例:

  1. function Create(n)  
  2.    local function foo1()  
  3.       print(n)  
  4.    end  
  5.    local function foo2()  
  6.       nn = n + 10  
  7.    end  
  8.    return foo1,foo2  
  9. end  
  10. f1,f2 = Create(1979)  
  11. f1() -- 打印1979  
  12. f2()  
  13. f1() -- 打印1989  
  14. f2()  
  15. f1() -- 打印1999 

f1,f2這兩個閉包的原型分別是Create中的內嵌函數foo1和foo2,而foo1和foo2引用的upvalue是同一個,即Create的局部變量n。前面已說過,執行完Create調用后,閉包會把堆棧上n的值復制出來,那么是否f1和f2就分別擁有一個n的拷貝呢?其實不然,當Lua發現兩個閉包的upvalue指向的是當前堆棧上的相同變量時,會聰明地只生成一個拷貝,然后讓這兩個閉包共享該拷貝,這樣任一個閉包對該upvalue進行修改都會被另一個探知。

上述例子很清楚地說明了這點:每次調用f2都將upvalue的值增加了10,隨后f1將更新后的值打印出來。upvalue的這種語義很有價值,它使得閉包之間可以不依賴全局變量進行通訊,從而使代碼的可靠性大大提高。

閉包在創建之時其upvalue就已經不在堆棧上的情況也有可能發生,這是因為內嵌函數可以引用更外層外包函數的局部變量:

  1. function Test(n)  
  2.    local function foo()  
  3.       local function inner1()  
  4.          print(n)  
  5.       end  
  6.       local function inner2()  
  7.          nn = n + 10  
  8.       end  
  9.       return inner1,inner2  
  10.    end  
  11.    return foo  
  12. end  
  13.  
  14. t = Test(1979)  
  15. f1,f2 = t()  
  16. f1()        -- 打印1979  
  17. f2()  
  18. f1()        -- 打印1989  
  19. g1,g2 = t()  
  20. g1()        -- 打印1989  
  21. g2()  
  22. g1()        -- 打印1999  
  23. f1()        -- 打印1999 

執行完t = Test(1979)后,Test的局部變量n就“死”了,所以當f1,f2這兩個閉包被創建時堆棧上根本找不到n的蹤影,這叫它們如何取得n的值呢?呵呵,不要忘了Test函數的n不僅僅是inner1和inner2的upvalue,同時它也是foo的upvalue。t = Test(1979)之后,t這個閉包一定已經把n妥善保存好了,之后f1、f2如果在當前堆棧上找不到n就會自動到它們的外包閉包(姑且這么叫)的upvalue引用數組中去找,并把找到的引用值拷貝到自己的upvalue引用數組中。

仔細觀察上述代碼,可以判定g1和g2與f1和f2共享同一個upvalue。這是為什么呢?其實,g1和g2與f1和f2都是同一個閉包(t)創建的,所以它們引用的upvalue(n)實際也是同一個變量,而剛才描述的搜索機制則保證了***它們的upvalue引用都會指向同一個地方。

小結:關于LUA閉包操作學習教程的內容介紹完了,希望通過本文的學習能對你有所幫助!

責任編輯:zhaolei 來源: cppblog
相關推薦

2011-08-23 17:06:03

2011-08-23 16:37:05

Lua數學庫

2011-08-23 15:34:56

Lua模式 匹配

2011-08-24 14:14:13

LUA環境 配置

2011-08-24 13:27:07

Lua 游戲C接口腳本

2011-08-23 16:48:41

Lua 5.1API 函數

2011-08-24 15:34:44

MinGWLua環境配置

2011-08-24 15:42:38

LUA源代碼

2011-08-25 15:41:42

Lua源碼

2011-08-23 13:54:10

LUA全局變量

2011-08-23 16:14:27

Lua函數庫函數

2011-08-23 15:57:21

Lua元表元方法

2011-08-24 11:08:09

Lua

2016-09-14 09:20:05

JavaScript閉包Web

2011-08-23 17:33:08

LuaMetatable

2011-08-25 16:20:33

Lua腳本變量

2011-08-25 17:01:50

LUA網游游戲

2011-05-25 14:48:33

Javascript閉包

2009-07-22 07:43:00

Scala閉包

2011-08-23 14:33:51

Lua捕獲字符串
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日本久久精品视频 | 精品久久久久久亚洲精品 | 国产一区二区中文字幕 | 国产亚洲精品久久yy50 | 国产亚洲一区二区三区在线观看 | 欧美日韩国产一区二区三区不卡 | 97国产爽爽爽久久久 | 日韩一区二区三区精品 | 久久国产精品亚洲 | 亚洲一区中文字幕在线观看 | 欧美高清一区 | 亚洲精品久久久久久一区二区 | 中文字幕在线免费观看 | 欧美另类视频 | 中文字幕久久精品 | 黄色大片免费观看 | 久久99国产精一区二区三区 | 超碰在线97国产 | 中文字幕视频在线 | 亚洲视频二区 | 国产精品免费在线 | 午夜三级视频 | 男人天堂免费在线 | 日韩三级在线 | 国产精品s色 | 国产亚洲精品精品国产亚洲综合 | 怡红院免费的全部视频 | 波多野结衣一二三区 | 先锋资源网站 | 亚洲激精日韩激精欧美精品 | 99久久精品免费看国产小宝寻花 | 一区二区三区视频 | 欧美午夜精品理论片a级按摩 | 成人影 | 亚洲在线电影 | 黄色亚洲网站 | 亚洲人成人一区二区在线观看 | 亚洲网站在线观看 | www久久久 | 国产精品美女 | 影音av |