1.函數是Lua中的第一值
在Lua中,函數能夠像數字和字串那樣,儲存在變數和table中,也能作為參數進行傳遞,也可以作為函數的傳回值。
2.詞法域
一個函數可以訪問外部函數的變數。
3.匿名函數
函數與所有其他值一樣都是匿名的,即他們都沒有名稱,我們可以把函數看成一個值。可以將它賦給某個變數。
foo=function ( x )return 2*xendprint(foo(2))
4.函數作為參數傳遞
在table中有一個sort函數,接受一個table值和一和函數作為參數。例如:
classmate={{name="Jack",grade="90"},{name="Rose",grade="80"},{name="Tomas",grade="88"},{name="Mary",grade="60"}}foo=function () for k,val in ipairs(classmate) do print(val.name.."-"..val.grade)endendprint("Before sort:")foo()print("SortByName:")table.sort(classmate,function(a,b) return(a.name)>b.name end)foo()print("SortByGrade:")table.sort(classmate,function(a,b) return(a.grade)>b.grade end)foo()
運行結果:
這時候匿名函數就體現了很好的便捷性。
再看一個例子,函數求導。
導數的定義就是(f(x+d)-f(x))/d,其中d趨於無窮小。下面是lua實現。
function derivative( f,delta )delta=delta or 1e-4return function(x)return(f(x+delta)-f(x))/deltaendendc=derivative(math.sin)print(math.cos(10),c(10))
個人感覺有點亂--
5.閉合函數
若將一個函數寫在另一個函數之內,那麼這個位於內部的函數可以訪問外部函數中的局部變數,這種特徵稱為“詞法域”。
一個計數器的例子:
function newCounter()local i=0return function()i=i+1return iendendc1=newCounter()print(c1())print(c1())print(c1())
對於newCounter中的匿名函數,i為“非局部變數”,用於保持一個計數器,在匿名函數調用i的時候,看似已經超出了範圍,實際上Lua會以closure的概念來正確的處理這種情況。這就是閉包。簡單的講,一個closure就是一個函數加上該函數所需方位的所有“非局部的變數”。如果再次調用newCounter,它就會建立一個新的局部變數i,從而得到一個新的closure。
接著上面的程式,執行下面的語句:
c2=newCounter()print(c2())print(c2())
c1和c2為一個函數所建立的兩個不同的closure,他們個字擁有局部變數i的獨立執行個體。
6.非全域函數
非全域函數指的是把函數當作一般的變數,如整數,字串。將其儲存在table欄位中和局部變數中。例如:
Lib={}Lib.add=function(x,y) return x+y endLib.mul=function(x,y) return x-y endprint(Lib.add(1,2))print(Lib.mul(3,100))
還有一個遞迴調用的例子
--local fact=function(n)local function fact(n)if n==0 then return 1else return n*fact(n-1)endendprint(fact(100))
注釋的那一行是報錯的寫法,因為在遞迴調用的時候發現fact沒有定義,後者是正確的。
7.正確的尾調用
尾調用類似於goto的函數調用,當一個函數調用的是另一個函數的最後的一個動作時,該調用才算尾調用。
例如,f在調用完g之後就再也無其他事情可做。
function f(x) <some operation> return g(x) end
Lua中尾調用的機制就是在確定為尾調用之後,執行完尾調函數就不需要返回原函數了,程式也不需要儲存任何關於該函數的棧資訊,不耗費任何棧空間,在lua中稱為尾調用消除。
尾調用的一個很大的應用就是有限狀態機器了,從這個狀態跳到令一個狀態,然後可以無窮跳,而不用考慮棧的溢出,是不是很棒!