1. 程式人生 > >(6)LUA程式設計-編譯執行與錯誤(compile 、run & error)處理

(6)LUA程式設計-編譯執行與錯誤(compile 、run & error)處理

1.編譯問題

----------------------------

----------------------------

首先我們談一下編譯的問題,LUA的執行,是將原始碼轉換成中間程式碼的形式執行的。

說到這裡,也許會有不少人會問,LUA不是一種解釋型語言,沒錯!LUA就是一門解釋型動態語言指令碼。其實區別一門語言是否為解釋型語言,關鍵在不在於它是否被編譯,而是它的編譯器是否是執行時庫的一部分,是否具備動態執行程式碼的能力。所以LUA是程式碼是需要被轉成中間程式碼被LUA編譯器執行的。

1.1LUA當中的常見編譯函式

1.1.1 loadfile

LUA中,有dofile這樣子函式,用於載入LUA程式碼檔案,用法:dofile(filename), eg.dofile('xxx.lua');但其實dofile是呼叫了更深層的loadfile函式,與dofile類似,loadfile同樣是用於載入編譯一個程式碼塊(chunck),但是除此之外loadfile還返回一個函式,同時如果編譯出錯,loadfile還會返回nil及相關錯誤資訊。dofile呼叫loadfile的程式碼如下:

funciton dofile(filename)

local f = assert(loadfile(filename));

return f();

end

說明:1.assert用判斷loadfile是否成功,有點像java/javascript裡邊的一個try{}catch{},用以引發錯誤資訊。

2.dofile相對loadfile來說,每次呼叫,都需要重新編譯一次被載入的程式碼塊,而一次呼叫loadfile可以多次呼叫loadfile返回的函式引用。

1.1.2 loadstring

與loadfile類似,loadstirng 是用於載入lua程式碼塊的字串形式,並返回由該程式碼塊組成的一個函式。

如:f = loadstring("i = i+1");

i = 0;

f() -->1

f()-->2

上面等價於

i = 0;

loadstring("i = i+1")( );-->1

loadstring("i = i+1")( );-->2

為了讓錯誤顯示得更清楚,我們可以為loadstring 的返回值加上 assert,即 assert(loadstring(s))()的形式

LUA將所以有獨立的程式碼塊都看成是一個匿名函式的函式體,而函式有可變引數這個特徵(前面講到的三大特徵之一),所以loadstring函式所返回的函式,也允許傳入引數。只需要在loadstirng(s)的s當中宣告一個local變數用於儲存可變引數,即可

f = loadstring("local xx = ... return xx "); f('hello') -- hello

------------------------------------------

注:f = loadstring('i = i+1') 基本上等價於 f = function() i = i+1 end

但是兩者有極大的區別:

1.從詞法域上來講,loadstring 的方式,不涉及詞法域,舉例如下

i = 32

local i = 0

f = loadstring("i = i+ 1");

g = function() i=i+1 end;

f() --33

g() -- 1

2.從編譯次數的角度來說,loadstring 每次呼叫都要重新編譯一次,而function的形式,只編譯一次。

1.1.3 load

與loadfile和loadstring相比,load函式有所不同。loadfile和loadstring 是分別從檔案和字串中讀取程式塊,但load則不同,如果載入的程式碼塊過大,記憶體空間不夠,用load則可以解決問題,它接收一次讀取器函式,可以將一個程式塊分多幾讀取,通過反覆呼叫“讀取器函式”,直到返回nil為止。

1.1.4 loadlib

眾所周知,動態連結機制並非ansi c 標準的一部分,LUA用C編寫的,不會包含無法用ANSI C實現的所有機制,但是動態連結機制除外,LUA將動態連結機制作為實現其他機制的母機制,通過動態機制,LUA可以載入任何LUA不支援的機制。

LUA載入動態連結庫,主要用到函式package 下的loadlib,用法如下

local dynaLinkLibPath = ''/usr/local/lib/lua/5.0/socket.so' --linux下動態連結庫字尾為so

local f = package.loadlib(path,'luaopen_socket');

package.loadlib通過指定載入庫的路徑,以及C函式名,返回一個LUA函式,用以被LUA程式碼呼叫。loadlib將結合我們後面要講的require函式使用,require用於搜尋指定庫,loadlib用於載入搜到的庫。

2.錯誤處理,異常封裝,錯誤跟蹤

2.1 LUA當中錯誤處理一般情況是

f = io.open(file);

if not f then

<error code here>

else

....

end

當然LUA提供了一個內建引發錯誤的函式,即上面講到的assert函式

它接收到兩個引數,第一個引數是lua的程式碼塊,可以是一個表示式,一個函式呼叫的返回結果,第二個引數是一個字串,用於提供 第一個引數程式碼執行時出錯的提示

2.2異常封裝

LUA提供一種pcall保護模式,pcall是一個函式,引數是一個函式,pcall返回兩個值,第一個是函式引數是否呼叫成功,呼叫失敗返回false,否則返回true.第二個引數是呼叫失敗的錯誤資訊。

local status ,err = pcall(function() error({code=500}) end);--可以自定義出錯程式碼

print(err.code)--打印出錯程式碼

2.3 錯誤跟蹤

error()函式,可以接收一個字串引數,用於提示出錯原因,如error("the wrong string unexpected!!");,也可以接收兩個引數,第一個引數用於提示出錯原因,第二個引數用於表示具體出錯的級別,可以跟蹤錯誤出現的位置。舉例如下:

function fuck(s)

if type(s) ~= 'string' then

error('string expected!!')

else ....

end

如果主函式呼叫了fuck()函式,並傳入一個122number型別的數值,fuck將出錯,但是並不能顯示出錯的層次,並不知道出錯在哪裡,所以將上面程式碼改成

function fuck(s)

if type(s) ~= 'string' then

error('string expected!!',2)

else ....

end

注:在error函式加入第二個引數2,那麼出錯時將提示具體出錯的位置,便於除錯跟蹤!!!

完畢!!下節將講解lua程式設計基礎篇的最後一小節,內容也是相當重要!!也難理解!!

----------------好了---本節到此結束,下一節將講解-(7)LUA程式設計-協同程式(coroutine)------------

LUA技術交流群,請加Q群:139315537,加入請註明來源。