luaを使用してtry-catch例外キャプチャを実現します

Luaは、例外処理をキャプチャするためのtry-catch構文をネイティブに提供しませんがpcall/xpcall、プロテクトモードでLua関数を実行するためのインターフェイスを提供します。

したがって、try-catchブロックのキャプチャメカニズムは、これら2つのインターフェイスをカプセル化することで実現できます。

最初に、カプセル化後のtry-catchの使用を確認できます。

try
{
    -- try 代码块
    function ()
        error("error message")
    end,

    -- catch 代码块
    catch 
    {
        -- 发生异常后,被执行
        function (errors)
            print(errors)
        end
    }
}

上記のコードでは、tryブロックで例外が考慮され、エラーメッセージがスローされ、catchでキャプチャされ、エラーメッセージが出力されて表示されます。

pcall/xpcall例外情報をキャプチャするために使用されるカプセル化に加えて、Luaの関数呼び出し構文機能も使用します。パラメータを1つだけ渡す場合、Luaはテーブルタイプを直接渡して省略できます。()

実際、tryの背後にある全体{...}は単なるテーブルであり、パラメーターとして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
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に戻ると、上記の実装により、実際には最終処理が内部にあることがわかります。この関数はtry{}コードブロック用であり、実行が成功したかどうかに関係なく、finallyブロックで実行されます。

言い換えると、実際には、上記の実装では、完全なサポート構文は次のとおりですtry-catch-finally。mode。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
    }
}

または最後にブロックするだけです:

try
{
    -- try 代码块
    function ()
        return "info"
    end,

    -- finally 代码块
    finally 
    {
        -- 由于此try代码没发生异常,因此ok为true,errors为返回值: "info"
        function (ok, errors)
        end
    }
}

処理は、最終的にtry inで通常の戻り値を取得できます。実際、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.run1行だけで、操作が成功したかどうかを判断するために値を返す必要はありません。操作が失敗した後、xmakeは自動的に例外をスローし、プログラムを中断してエラーをプロンプトするためです。

操作が失敗した後、xmakeを直接中断せずに実行を継続したい場合は、自分で試してみることができます。

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

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

エラーメッセージをキャプチャする場合は、別のキャッチを追加できます。

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、実装の関連する完全なソースコードが添付されています:


個人ホームページ:TBOOXオープンソースプロジェクト
オリジナルソース:http//tboox.org/cn/2016/12/14/try-catch/

おすすめ

転載: blog.csdn.net/waruqi/article/details/53649634