lua原生並沒有提供try-catch的語法來捕獲異常處理,但是提供了pcall/xpcall
等介面,可在保護模式下執行lua函式。
因此,可以通過封裝這兩個介面,來實現try-catch塊的捕獲機制。
我們可以先來看下,封裝後的try-catch使用方式:
try
}
上面的**中,在try塊內部認為引發了乙個異常,並且丟擲錯誤訊息,在catch中進行了捕獲,並且將錯誤訊息進行輸出顯示。
這裡除了對pcall/xpcall
進行了封裝,用來捕獲異常資訊,還利用了lua的函式呼叫語法特性,在只有乙個引數傳遞的情況下,lua可以直接傳遞乙個table型別,並且省略()
其實try後面的整個都是乙個table而已,作為引數傳遞給了try函式,其具體實現如下:
function
try(block)
-- get the try function
local try = block[1]
assert(try)
-- get catch and finally functions
local funcs = block[2]
if funcs and block[3] then
table.join2(funcs, block[2])
end-- try to call it
local ok, errors = pcall(try)
ifnot ok then
-- run the catch function
if funcs and funcs.catch then
funcs.catch(errors)
endend-- run the finally function
if funcs and funcs.finally then
funcs.finally(ok, errors)
end-- ok?
if ok then
return errors
endend
可以看到這裡用了pcall
來實際呼叫try塊裡面的函式,這樣就算函式內部出現異常,也不會中斷程式,pcall
會返回false表示執行失敗
並且返回實際的出錯資訊,如果想要自定義格式化錯誤資訊,可以通過呼叫xpcall來替換pcall,這個介面與pcall相比,多了個錯誤處理函式:
local ok, errors = xpcall(try, debug.traceback)
你可以直接傳入debug.traceback
,使用預設的traceback處理介面,也可以自定義乙個處理函式:
-- traceback
function
my_traceback
(errors)
-- make results
local level = 2
while
true
do-- get debug info
local info = debug.getinfo(level, "sln")
-- end?
ifnot info or (info.name and info.name == "xpcall") then
break
end-- function?
if info.what == "c"
then
results = results .. string.format(" [c]: in function '%s'\n", info.name)
elseif info.name then
results = results .. string.format(" [%s:%d]: in function '%s'\n", info.short_src, info.currentline, info.name)
elseif info.what == "main"
then
results = results .. string.format(" [%s:%d]: in main chunk\n", info.short_src, info.currentline)
break
else
results = results .. string.format(" [%s:%d]:\n", info.short_src, info.currentline)
end-- next
level = level + 1
end-- ok?
return results
end-- 呼叫自定義traceback函式
local ok, errors = xpcall(try, my_traceback)
回到try-catch上來,通過上面的實現,會發現裡面其實還有個finally的處理,這個的作用是對於try{}
**塊,不管是否執行成功,都會執行到finally塊中
也就說,其實上面的實現,完整的支援語法是:try-catch-finally
模式,其中catch和finally都是可選的,根據自己的實際需求提供
例如:
try
, -- finally **塊
finally
中存在異常,ok為true,errors為錯誤資訊,否則為false,errors為try中的返回值
end }
}
或者只有finally塊:
try
}
處理可以在finally中獲取try裡面的正常返回值,其實在僅有try的情況下,也是可以獲取返回值的:
-- 如果沒發生異常,result 為返回值:"***x",否則為nil
local result = try
可以看到,這個基於pcall的try-catch-finally
異常捕獲封裝,使用上還是非常靈活的,而且其實現相當的簡單
這也充分說明了lua是一門已非常強大靈活,又非常精簡的語言。
在xmake的自定義指令碼、外掛程式開發中,也是完全基於此異常捕獲機制
這樣使得擴充套件指令碼的開發非常的精簡可讀,省去了繁瑣的if err ~= nil then
返回值判斷,在發生錯誤時,xmake會直接丟擲異常進行中斷,然後高亮提示詳細的錯誤資訊。
例如:
target("test")
set_kind("binary")
add_files("src/*.c")
-- 在編譯完ios程式後,對目標程式進行ldid簽名
after_build(function
(target)
) os.run("ldid -s %s", target:targetfile())
end
只需要一行os.run
就行了,也不需要返回值判斷是否執行成功,因為執行失敗後,xmake會自動拋異常,中斷程式並且提示錯誤
如果你想在執行失敗後,不直接中斷xmake,繼續往下執行,可以自己加個try快就行了:
target("test")
set_kind("binary")
add_files("src/*.c")
after_build(function
(target)
) try
end
如果還想捕獲出錯資訊,可以再加個catch:
target("test")
set_kind("binary")
add_files("src/*.c")
after_build(function
(target)
) try
}end
不過一般情況下,在xmake中寫自定義指令碼,是不需要手動加try-catch的,直接呼叫各種api,出錯後讓xmake預設的處理程式接管,直接中斷就行了。。
個人主頁:tboox開源工程
原文出處:
lua以xpcall實現try catch功能
列印錯誤資訊 local function trackback errmsg local track text debug.traceback tostring errmsg 6 print trackback print track text,lua error print trackback l...
lua中xpcall實現try catch功能
local status,msg xpcall main,g trackback for ccluaengine traceback function g trackback msg local message debug.traceback msg,3 if qy.debug then self ...
lua以xpcall實現try catch功能
列印錯誤資訊 local function trackback errmsg local track text debug.traceback tostring errmsg 6 print trackback print track text,lua error print trackback l...