程序運行中錯誤處理是必要的,在我們進(jìn)行文件操作,數(shù)據(jù)轉(zhuǎn)移及web service 調(diào)用過程中都會出現(xiàn)不可預(yù)期的錯誤。如果不注重錯誤信息的處理,就會造成信息泄露,程序無法運行等情況。
任何程序語言中,都需要錯誤處理。錯誤類型有:
語法錯誤
運行錯誤
語法錯誤通常是由于對程序的組件(如運算符、表達(dá)式)使用不當(dāng)引起的。一個簡單的示例如下:
-- test.lua 文件 a == 2
以上代碼執(zhí)行結(jié)果為:
lua: test.lua:2: syntax error near '=='
正如你所看到的,以上出現(xiàn)了語法錯誤,一個 "=" 號跟兩個 "=" 號是有區(qū)別的。一個 "=" 是賦值表達(dá)式兩個 "=" 是比較運算。
另外一個示例:
for a= 1,10 print(a) end
執(zhí)行以上程序會出現(xiàn)如下錯誤:
lua: test2.lua:2: 'do' expected near 'print'
語法錯誤比程序運行錯誤更簡單,運行錯誤無法定位具體錯誤,而語法錯誤我們可以很快的解決,如以上示例我們只要在for語句下添加 do 即可:
for a= 1,10 do print(a) end
運行錯誤是程序可以正常執(zhí)行,但是會輸出報錯信息。如下示例由于參數(shù)輸入錯誤,程序執(zhí)行時報錯:
function add(a,b) return a+b end add(10)
當(dāng)我們編譯運行以下代碼時,編譯是可以成功的,但在運行的時候會產(chǎn)生如下錯誤:
lua: test2.lua:2: attempt to perform arithmetic on local 'b' (a nil value) stack traceback: test2.lua:2: in function 'add' test2.lua:5: in main chunk [C]: ?
lua 里調(diào)用函數(shù)時,即使實參列表和形參列表不一致也能成功調(diào)用,多余的參數(shù)會被舍棄,缺少的參數(shù)會被補(bǔ)為 nil。
以上報錯信息是由于參數(shù) b 被補(bǔ)為 nil 后,nil 參與了 + 運算。
假如 add 函數(shù)內(nèi)不是 "return a+b" 而是 "print(a,b)" 的話,結(jié)果會變成 "10 nil" 不會報錯。
我們可以使用兩個函數(shù):assert 和 error 來處理錯誤。示例如下:
local function add(a,b) assert(type(a) == "number", "a 不是一個數(shù)字") assert(type(b) == "number", "b 不是一個數(shù)字") return a+b end add(10)
執(zhí)行以上程序會出現(xiàn)如下錯誤:
lua: test.lua:3: b 不是一個數(shù)字 stack traceback: [C]: in function 'assert' test.lua:3: in local 'add' test.lua:6: in main chunk [C]: in ?
示例中assert首先檢查第一個參數(shù),若沒問題,assert不做任何事情;否則,assert以第二個參數(shù)作為錯誤信息拋出。
語法格式:
error (message [, level])
功能:終止正在執(zhí)行的函數(shù),并返回message的內(nèi)容作為錯誤信息(error函數(shù)永遠(yuǎn)都不會返回)
通常情況下,error會附加一些錯誤位置的信息到message頭部。
Level參數(shù)指示獲得錯誤的位置:
Level=1[默認(rèn)]:為調(diào)用error位置(文件+行號)
Level=2:指出哪個調(diào)用error的函數(shù)的函數(shù)
Level=0:不添加錯誤位置信息
Lua中處理錯誤,可以使用函數(shù)pcall(protected call)來包裝需要執(zhí)行的代碼。
pcall接收一個函數(shù)和要傳遞給后者的參數(shù),并執(zhí)行,執(zhí)行結(jié)果:有錯誤、無錯誤;返回值true或者或false, errorinfo。
語法格式如下
if pcall(function_name, ….) then -- 沒有錯誤 else -- 一些錯誤 end
簡單示例:
> =pcall(function(i) print(i) end, 33) 33 true > =pcall(function(i) print(i) error('error..') end, 33) 33 false stdin:1: error..
這里注意對返回值的邏輯判斷:
> function f() return false,2 end > if f() then print '1' else print '0' end 0
pcall以一種"保護(hù)模式"來調(diào)用第一個參數(shù),因此pcall可以捕獲函數(shù)執(zhí)行中的任何錯誤。
通常在錯誤發(fā)生時,希望落得更多的調(diào)試信息,而不只是發(fā)生錯誤的位置。但pcall返回時,它已經(jīng)銷毀了調(diào)用桟的部分內(nèi)容。
Lua提供了xpcall函數(shù),xpcall接收第二個參數(shù)——一個錯誤處理函數(shù),當(dāng)錯誤發(fā)生時,Lua會在調(diào)用桟展開(unwind)前調(diào)用錯誤處理函數(shù),于是就可以在這個函數(shù)中使用debug庫來獲取關(guān)于錯誤的額外信息了。
debug庫提供了兩個通用的錯誤處理函數(shù):
debug.debug:提供一個Lua提示符,讓用戶來檢查錯誤的原因
debug.traceback:根據(jù)調(diào)用桟來構(gòu)建一個擴(kuò)展的錯誤消息
>=xpcall(function(i) print(i) error('error..') end, function() print(debug.traceback()) end, 33) 33 stack traceback: stdin:1: in function <stdin:1> [C]: in function 'error' stdin:1: in function <stdin:1> [C]: in function 'xpcall' stdin:1: in main chunk [C]: in ? false nil
xpcall 使用示例 2:
function myfunction () n = n/nil end function myerrorhandler( err ) print( "ERROR:", err ) end status = xpcall( myfunction, myerrorhandler ) print( status)
執(zhí)行以上程序會出現(xiàn)如下錯誤:
ERROR: test2.lua:2: attempt to perform arithmetic on global 'n' (a nil value) false