使用lua實現try catch異常捕獲

2021-09-20 08:47:05 字數 4186 閱讀 6247

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...