1. 程式人生 > >使用lua實現try-catch異常捕獲

使用lua實現try-catch異常捕獲

lua原生並沒有提供try-catch的語法來捕獲異常處理,但是提供了pcall/xpcall等介面,可在保護模式下執行lua函式。

因此,可以通過封裝這兩個介面,來實現try-catch塊的捕獲機制。

我們可以先來看下,封裝後的try-catch使用方式:

try
{
    -- try 程式碼塊
    function ()
        error("error message")
    end,

    -- catch 程式碼塊
    catch 
    {
        -- 發生異常後,被執行
        function (errors)
            print
(errors) end } }

上面的程式碼中,在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) if not ok then -- run the catch function if funcs and funcs.catch then
funcs.catch(errors) end end -- run the finally function if funcs and funcs.finally then funcs.finally(ok, errors) end -- ok? if ok then return errors end end

可以看到這裡用了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?
        if not 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
{
    -- try 程式碼塊
    function ()
        error("error message")
    end,

    -- catch 程式碼塊
    catch 
    {
        -- 發生異常後,被執行
        function (errors)
            print(errors)
        end
    },

    -- finally 程式碼塊
    finally 
    {
        -- 最後都會執行到這裡
        function (ok, errors)
            -- 如果try{}中存在異常,ok為true,errors為錯誤資訊,否則為false,errors為try中的返回值
        end
    }
}

或者只有finally塊:

try
{
    -- try 程式碼塊
    function ()
        return "info"
    end,

    -- finally 程式碼塊
    finally 
    {
        -- 由於此try程式碼沒發生異常,因此ok為true,errors為返回值: "info"
        function (ok, errors)
        end
    }
}

處理可以在finally中獲取try裡面的正常返回值,其實在僅有try的情況下,也是可以獲取返回值的:

-- 如果沒發生異常,result 為返回值:"xxxx",否則為nil
local result = try
{
    function ()
        return "xxxx"
    end
}

可以看到,這個基於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
        {
            function ()
                os.run("ldid -S %s", target:targetfile())
            end
        }
    end

如果還想捕獲出錯資訊,可以再加個catch:

target("test")
    set_kind("binary")
    add_files("src/*.c")

    after_build(function (target))
        try
        {
            function ()
                os.run("ldid -S %s", target:targetfile())
            end,
            catch 
            {
                function (errors)
                    print(errors)
                end
            }
        }
    end

不過一般情況下,在xmake中寫自定義指令碼,是不需要手動加try-catch的,直接呼叫各種api,出錯後讓xmake預設的處理程式接管,直接中斷就行了。。

最後附上try-catch-finally實現的相關完整原始碼:

相關推薦

使用lua實現try-catch異常捕獲

lua原生並沒有提供try-catch的語法來捕獲異常處理,但是提供了pcall/xpcall等介面,可在保護模式下執行lua函式。 因此,可以通過封裝這兩個介面,來實現try-catch塊的捕獲機制。 我們可以先來看下,封裝後的try-catch使用方式:

.net try catch 異常捕獲的正確使用姿勢。。

很慚愧,寫了好多年的程式碼, 最基本的try catch 才剛剛會正確的使用, 以前只能說叫會用, 但是用法不正確。 先說說,異常的3種使用方式。 見下面的程式碼。 public static int Method1() {

javascript中的try catch異常捕獲機制

                          1.跟java一樣,javascript也具有try catch塊,進行異常捕獲的機制。              (1)典型的try cat

php中為什麼要用try catch捕獲異常

Try - 使用異常的函式應該位於 "try" 程式碼塊內。如果沒有觸發異常,則程式碼將照常繼續執行。但是如果異常被觸發,會丟擲一個異常。 Catch - "catch" 程式碼塊會捕獲異常,並建立一個包含異常資訊的物件。 讓我們觸發一個異常: //建立可丟擲一個異常的函式 function che

多此一舉, C實現 try-catch

trycatch 線程安全 C 異常處理 在做NtyTcp的時候,有一些,就想用c來實現一套try-catch異常處理子系統。不討論C語言本身為什麽不加try-catch,每個開發的朋友對於這個問題,都能說出一大堆的理由。其實我也是不太喜歡強行在c中加入一個try-catch。就像把try-c

try catch 異常處理

學習code: int main(int argc, char* argv[])...{  try...{... ...  }  catch(std::exception& e) ...{    std::cerr <<"Exception caught

try catch異常丟擲與spring事務回滾策略相關

將異常捕獲,並且在catch塊中不對事務做顯式提交(或其他應該做的操作如關閉資源等)=生吞掉異常; spring的事務邊界是在呼叫業務方法之前開始的,業務方法執行完畢之後來執行commit or rollback(Spring預設取決於是否丟擲runtime異常). 

SQL Server Try Catch 異常捕捉

背景 今天遇到一個關於try catch 使用比較有意思的問題。如下一段程式碼: SELECT @@TRANCOUNT AS A BEGIN TRY BEGIN TRAN SELECT @@TRANCO

C語言實現try catch處理

我們都知道,在Java、C#等高階程式語言中,都自帶有異常處理機制,其基本結構如下: try{ 程式語句; }catch(Exception ex){ 異常處理; } 這樣做不但可以防止程式異常終止,而且在出現錯誤時可以及時作一些釋放資源處理,對程式能繼續健壯的執行下去尤

C# .net程式設計基礎-try-catch異常處理-階乘示例

    在軟體開發過程中,程式異常是十分常見的,也就是我們常說的BUG,因此需要我們對不可預期的異常進行處理。     異常處理其實很簡單,最開始我也就得很難,不用怕、真的挺簡單的,真正理解了頂多也就一個try-catch語句和throw語句。     try-catch語

Thinkphp try{}catch()異常處理的寫法

最近在專案開發中 異常處理捕獲不到,查了下關於異常處理的資料,還是名稱空間的問題 public function del ($id) {//在模型中丟擲異常 if ( !$id || !is_array($id) ) { E('ID不合

try...catch異常處理使用注意——包含程式碼過多

Java中使用try…catch來處理異常,今天在debug一段用try..catch處理的程式碼段,除錯時throws Exception, 感覺丟擲的異常有問題,但是又很難對出現問題的地方進行識別定

spring的註解事務與try catch 異常處理

Spring的預設事務機制,當出現unchecked異常時候回滾,checked異常的時候不會回滾; 異常中unchecked異常包括error和runtime異常,需要try catch或向上丟擲的異常為checked異常比如IOException,也就是說程式丟擲r

try catch異常的一些注意的地方

網上的一些總結記錄:1 try、catch、finally語句中,在如果try語句有return語句,則返回的之後當前try中變數此時對應的值,此後對變數做任何的修改,都不影響try中return的返回值2 如果finally塊中有return 語句,則返回try或catch

Java異常捕獲之一道try-catch-finally語句題

span pri div system 處理機 out nal exception for 今天,學習了try-catch-finally語句,本來覺得蠻簡單、易懂的。搜了一道相關類型的題。結果信心被潑了盆冷水。先把題Mark一下,出去透透風。 1 public cla

PHP 使用try catch,捕獲異常

get type 設置 html 異常信息 utf-8 tex http mes <?php header(‘Content-type:text/html;charset=utf-8‘); $a = 1; $b = 2; try {

try catch 小結 , node的回調callback裏不能捕獲異常 , 不能被v8優化(現在能了),

容易 sin ejs called ack tro 崩潰 span 檢查 《深入淺出Nodejs》時,在第四章 - 異步編程中作者樸靈曾提到,異步編程的難點之一是異常處理,書中描述"嘗試對異步方法進行try/catch操作只能捕獲當次事件循環內的異常,對call back執

spring 聲明式事務中try catch捕獲異常

調用 color exception 代碼 狀態 新的 for 自定義 這樣的 原文:http://heroliuxun.iteye.com/blog/848122 今天遇到了一個這個問題 最近遇到這樣的問題,使用spring時,在業務層需要捕獲異常(特殊需要),當前一般

js中的異常捕獲 try{} catch{}(二)

事件輪循中,丟擲的異常資訊會丟失函式呼叫的路徑,所以每一步都要進行錯誤處理 function a(){ b(); } function b(){ c(); } function c(){ // setTimeout(() => { // throw new

try catch中開啟新的執行緒,不能捕獲執行緒裡面的異常

近期在review程式碼的時候發現,有些人為了圖方便,直接在程式碼引用的最外層放上一個try catch,以為可以捕獲一切異常,降低崩潰率。 事實上,如果try的是新開啟的一個執行緒,那麼這個執行緒裡面出現的異常是catch不到。也就是說在A執行緒中new B執行緒,B執行緒中出現的cr