1. 程式人生 > >一步步寫lua直譯器--閉包的由來

一步步寫lua直譯器--閉包的由來

原本函式在最開始的時候就實現了,但是後來發現了不少bug,都是由引數個數,返回值個數等引起的,比想象的要複雜一些。

lua中函式與閉包是緊密相連的。我們早在學習c或java的的時候,就認識了函式,學習諸如lua,python,js指令碼語言的時候才聽說閉包這個詞。在很長一段時間內我對閉包的概念都不是很理解,後來才慢慢清晰。現在親自實現指令碼語言後,才真正明白閉包的含義。

簡單一句話概括就是,函式是靜態的程式碼,閉包是動態執行的指令。這個好像類似執行緒和程序的概念。為什麼c或java裡沒有聽說過閉包的概念,反而在指令碼語言中才出現呢?這是因為c或java是編譯型語言,而指令碼語言大都是解釋型語言。

c或java語言被執行前先要經過編譯,涉及到函式時,其呼叫引數個數,型別,及返回值個數,型別必須和函式宣告時一致,否則編譯出錯。而指令碼語言是不需要編譯的,直接執行。本身指令碼語言最大的優點就是方便,靈活,沒有型別檢查,各種變數隨意賦值。這就意味著涉及到函式時有很大的變數。不僅沒有型別檢查,而且引數呼叫個數也可以與函式宣告時的不一致,即實參和形參不一致。指令碼語言的函式還有個很讚的亮點就是可以返回多個值,如果用c來返回值多個值,就是返回一個結構體,還是有點複雜,指令碼語言這點很爽有木有!

雖然指令碼語言很靈活,用起來很爽,但是要苦了實現指令碼語言編譯器的人,當然也包括我了。怎麼樣處理函式呼叫引數個數,返回值個數不一致的問題?我們可以這樣想,函式程式碼宣告之後永遠是不變的,而函式呼叫時卻有不同的情形。一個函式可以被呼叫N次,每次的呼叫引數和實際返回值的個數可能不一樣。例如下面的程式碼:

local f = function(a, b) return 10, a, b end
local a,b = f()
f(1)
local c = f(2,3) + 5

你看三種函式的呼叫卻都不一樣,第一個沒有傳入引數,需要兩個返回值。第二個傳入一個引數,不需要返回值。第三個傳入了2個引數,只需要一個返回值。我們可以把這三個函式看作是函式的三個例項。

也就是說例項是動態的程式碼,函式是靜態宣告的程式碼。每當呼叫函式時,我們就生成一個新的例項,我們可以把這個例項叫做閉包,而函式則是閉包的原型,因為閉包是由他生成的。

每個閉包必須要儲存其傳入的引數個數和需要返回值的個數,而函式的這些屬性是宣告時就決定好了的,以後不會有變化。介紹了這些背景,下篇我們正式講解函式的實現。

有問題可以在後面留言,或者加入QQ群 858791125 討論。