Lua語法特性



1.閉合函數(closure)

理論上來說,Lua的所以函數都應該稱之爲閉合函數,但是,這種反人類的做法,我們還是拋棄吧~

按書上的描述,一個閉合函數就是:一個函數加上該函數所需訪問的所有”非局部的變量“

理論什麼的,很煩人,來看看一個函數:

  1. function count()
  2.     local i = 0;
  3.     return function()
  4.               i = i + 1;
  5.               return i;
  6.            end
  7. end

這個count函數會返回另外一個函數,重點是,這個返回的函數會使用count函數的局部變量。
先來運行,看看效果,使用如下方式調用:

  1.     local func = count();
  2.     print(func());
  3.     print(func());
  4.     print(func());

輸出結果如下:

[LUA-print] 1
[LUA-print] 2
[LUA-print] 3

怎麼旁白不出來咆哮一下?(小若:…咳咳…爲毛線會這樣?!不應該全部都輸出1嗎?!)

 

在這裏,local i就屬於一個非局部變量,因爲它既不是全局變量,也不是單純的局部變量(因爲另外一個函數可以反問到它)。

再來回到定義,count函數裏的那個函數,加上非局部變量i,就構成了一個閉合函數了,就這麼簡單。

 

對於閉合函數而已,屬於它的非局部變量,並不是在調用它的時候臨時產生的,而是和它一起存在的。

所以每次調用閉合函數,非局部變量的值都不會被重置。

 

如果大家還是不太清楚,那麼,我們給這個閉合函數添加一個局部變量吧,修改count函數如下:

  1. function count()
  2.     return function()
  3.               local i = 999;
  4.               i = i + 1;
  5.               return i;
  6.            end
  7. end

這次,把i作爲這個內部函數的局部變量了,它不再是“非局部變量”。

仍然像這樣調用:

  1.     local func = count();
  2.     print(func());
  3.     print(func());
  4.     print(func());

 

輸出結果如下:

[LUA-print] 1000
[LUA-print] 1000
[LUA-print] 1000

陷入, 每一次i變量的值都是全新的。

閉合函數的用處可大着了,我們在開發過程中使用的頻率應該還算比較大的~

 

2.非全局函數

又是這種看着就反人類的名詞,非全局,那就是說,不是全局的函數(小若:廢你個話啊!)

來看看這樣的一個函數:

  1. local function mutou()
  2.    
  3. end

這就是一個非全局函數,但,這麼簡單的東西我可不會拿出來說~

 

這裏我想介紹一個“語法糖”,上面的mutou函數,其實相當於以下的代碼:

  1. local mutou;
  2. mutou = function ()
  3.    
  4. end

 

這就是我們函數的真實面貌,函數名稱其實也是一個變量名而已。

所以,有時候,我們在定義函數的時候,要注意一下順序。比如,這樣的兩個函數:

  1. local function mutou()
  2.     print("mutou");
  3.     return pangbai();
  4. end
  5. local function pangbai()
  6.     print("pangbai");
  7. end

mutou函數裏要調用pangbai函數。

在編譯的時候,mutou函數是編譯不過的,因爲這個時候pangbai函數未定義,換句話說,pangbai變量並不存在。

只要換一個方式就可以解決這個問題了:

  1. local mutou;
  2. local pangbai;
  3. mutou = function ()
  4.     print("mutou");
  5.     return pangbai();
  6. end
  7. pangbai = function ()
  8.     print("pangbai");
  9. end

這樣編譯就沒問題了,好吧,也許Lua裏不該叫編譯,反正,不會報語法錯誤了~

 

3.尾調用

好了,一個名詞比一個名詞要反人類。

尾調用的大致意思是:一個函數的調用是另一個函數的最後一個動作時,這個調用就稱之爲尾調用。

比如這樣的函數:

  1. function mutou()
  2.     return count();
  3. end

當mutou函數調用完count函數之後,就沒有其他事情要做了,所以,調用count函數,就屬於尾調用。

但,如果是這樣的函數:

  1. function mutou()
  2.     return count() + 1;
  3. end

 

這就不屬於尾調用,因爲調用完count函數之後,還要取得count的返回值,然後進行一次加法操作,這就不符合定義了。

 

尾調用有什麼意義呢?

進行尾調用時不會耗費多餘的棧空間,比如這樣一個經典的函數:

  1. function foo(n)
  2.     if n > 0 then
  3.         return foo(n - 1);
  4.     else
  5.         return "end";
  6.     end
  7. end

我們可以試試這樣調用:

  1. print(foo(99999));

 

結果就是不出所料地輸出了end字符串。

當n > 0時,函數就直接返回foo(n – 1),接着就沒有後續的動作了,所以這符合尾調用的定義。

因此,這個函數的調用不會引起棧溢出。

 

但,如果稍微改改,變成這樣:

  1. function foo(n)
  2.     if n > 0 then
  3.         return foo(n - 1) + 0;
  4.     else
  5.         return "end";
  6.     end
  7. end
發佈了12 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章