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.run
は1行だけで、操作が成功したかどうかを判断するために値を返す必要はありません。操作が失敗した後、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/