若將一個函數寫在另外一個函數以內,那麼這個位於內部的函數即可以訪問外部函數中的局部變量,這項特徵稱之爲「詞法域」。函數
假設有一個學生姓名的列表和一個對應於每一個姓名的年級列表,須要根據每一個學生的年紀來對他們的姓名進行排序。lua
names = {"Peter", "Paul", "Mary"} grades = {Mary = 10, Paul = 7, Peter = 8} table.sort(names, function(n1, n2) return grades[n1, n2] --比較年級 end) 如今,假設要單首創建一個函數來作這項工做: function sortbygrade(names,grades) table.sort(names, function(n1, n2) return grades[n1] > grade[n2] --比較年級 end) end 注意:上例中傳遞給sort的匿名函數能夠訪問參數grades,而grades是外部函數sortbygrade的局部變量。在這個匿名函數的內部,grades既不是全局變量也不是局部變量,將其稱爲一個「非局部的變量」。 由於函數是「第一類值」的緣由,因此容許這樣訪問。
function newCounter() local i = 0 return function () --匿名函數 i = i + 1 return i end end c1 = newCounter() print(c1()) -->1 print(c1()) -->2 這段代碼中,匿名函數訪問了一個「非局部的變量」i,該變量用於保持一個計數器。初看上去,因爲建立變量i的函數已經返回,因此以後每次調用匿名函數時,i都應是已超出了做用範圍的,可是,Lua會以closure的概念來處理。 簡單的講,一個closure就是一個函數加上該函數所需訪問的全部「非局部變量」。若是再次調用newCounter,那麼它會建立一個新的局部變量i,從而也將獲得一個新的closure。 c2 = newCounter() print(c2()) --- >1 print(c1()) --- >3 print(c2()) --- >2 所以,c1和c2是同一個函數所建立的兩個不一樣的closure,它們各自擁有局部變量i的獨立實例。
從技術上講,Lua中只有closure而不存在「函數」,由於函數自己就是一種特殊的closure【closure:指一個函數以及一系列這個函數會訪問到「非局部的變量」,所以若一個closure沒有那些會訪問的「非局部變量」,那他就是一個傳統概念中的「函數」】。spa
Lua中函數是存儲在普通變量中的,所以能夠輕易地從新定義某些函數,甚至是從新定義那些預約義的函數。一般當從新定義一個函數的時候,須要在新的實現中調用原來的那個函數。code
oldSin = math.sin math.sin = function(x) return oldSin(x * math.pi/180) end 假設要從新定義函數sin,使其參數能使用角度來代替原先的弧度。這個新函數就必須得轉換它的實參,並調用原來的sin函數完成真正的計算。