lua語言中的函數概念



1. 不同於C,lua中的函數是一種first-class-value,這意味着:
            lua中的函數可以視作一種"值"存儲到變量或table中;
            可以作爲其他函數的實參;
            可以作爲其他函數中的返回值;
            可以嵌套在其他函數中被構造創建,而無需在設計階段就定義好.
  
2. lua中的函數本身其實都是沒有名字的,也就是說通常討論的函數名(比如print),實際不過是持有某個函數的變量.
   所以,lua中函數的標準定義形式其實是:
            var = function (x) <body> end
   也就是說,一個函數定義其實就是一條賦值語句,這條語句首先是構造一種類型爲"函數"的值,然後將這個值賦給一個變量

3. 跟其他大部分語言一樣,lua遵循"詞法域"(即靜態作用域)的原則,又因爲lua函數是一種first-class-value,所以纔有了閉包(closure)的概念:
            一個閉包就是一個函數加上構造該函數時所需的所有"非局部的變量"(non-local variable)

   一個閉包的典型例子如下:
            function newCounter ()
                local i = 0
                return function ()  -- 匿名函數,也就是閉包
                    i = i + 1
                    return i
                end
            end
            c1 = newCounter()
            c2 = newCounter()
            print(c1)   -- 1
            print(c1)   -- 2
            print(c2)   -- 1
   這個例子中,變量i對於匿名函數來說,既不是全局變量,也不是局部變量,所以就被稱爲了"非局部的變量";
   調用函數newCounter的過程,其實就是創建一個閉包的過程;
   這裏要注意一點,函數名不帶括號賦值給一個變量,其實是表示共同持有某個函數,而函數名帶括號賦值給一個變量,其實是表示首先調用該函數,然後將該函數的返回值賦值給變量;
   所以以上例子中,c1和c2是同一個函數所創建的兩個獨立的閉包,也就是說,它們各自擁有獨立的i

4. lua函數中存在一種"尾調用"概念:
            當一個函數的最後一個動作是調用另外一個函數,並且包含了關鍵字"return",那麼這條調用就是該函數的尾調用。
   利用這種"尾調用"現象,lua實現了"尾調用消除"機制,原理就是:
            調用函數時,會在內存中形成一個"調用記錄",主要保存調用位置和內部變量信息,經過多次嵌套調用函數之後,內
            存中就會堆疊這些"調用記錄",形成一個"調用棧"。由於"尾調用"是所在函數的最後一步操作,一旦開始執行"尾調
            用"的函數,外層函數的調用記錄就不會再用到,所以就直接釋放這個調用記錄,然後再寫入"尾調用"的函數的調用
            記錄即可。
   這種"尾調用消除"機制的意義很明顯,那就是如果所有嵌套的函數都符合"尾調用",那麼真個嵌套調用的過程中,調用記錄同時只會有一項,這就大大節省了內存空間。
   一個典型的應用例子就是"尾遞歸",調用以下函數時,傳入任何數字都不會造成棧溢出:
            function foo (n)
                if n > 0 then
                    return foo (n - 1)
                end
            end
   遞歸非常耗費內存,因爲每次執行遞歸函數,就要往內存中增加一條調用記錄,所以很容易發生"棧溢出"錯誤。但對於"尾遞歸"來說,由於同一時刻只會存在一個調用記錄,所以永遠不
   會發生"棧溢出"問題。
  
           


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章