pcallによる保護付き呼び出し
pcallでエラーを安全に捕捉し、戻り値を解釈します。
「pcallによる保護付き呼び出し」はCoddyKit上の無料Lua Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはLua Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Lua Academyコースには全4レッスンが含まれています。
pcall の基本
pcall(f, ...) は、保護モードで引数 ... を付けて関数 f を呼び出します。f が成功すると、pcall は true に続けてすべての戻り値を返します。f がエラーになると、pcall は false に続けてエラーメッセージを返します。どちらの場合もプログラムは実行を継続します。
local function risky(x)
if x < 0 then error("negative input: " .. x) end
return math.sqrt(x)
end
local ok, result = pcall(risky, 9)
print(ok, result) -- true 3.0
ok, result = pcall(risky, -1)
print(ok, result) -- false ...: negative input: -1特定のエラーの捕捉
pcall の後でエラー値の型を確認し、エラーの種類ごとに異なる処理を行います。テーブルエラーには構造化されたデータがあり、文字列エラーにはメッセージがあります。常に両方のケースを処理してください。
local function op(errType)
if errType == "table" then
error({code=42, msg="structured error"})
else
error("plain string error")
end
end
local ok, err = pcall(op, "table")
if not ok then
if type(err) == "table" then
print("Code:", err.code, "Msg:", err.msg)
else
print("String error:", err)
end
end成功時の複数戻り値
成功時、pcall は最初の true に続けて、保護された関数のすべての戻り値を返します。複数の変数で受け取ってください。
local function compute(a, b)
return a + b, a * b, a - b
end
local ok, sum, product, diff = pcall(compute, 6, 4)
if ok then
print("sum:", sum, "product:", product, "diff:", diff)
-- sum: 10 product: 24 diff: 2
endpcall のネスト
pcall の呼び出しはネストできます。それぞれの pcall が独立した保護スコープを作成します。内側の pcall で発生したエラーは外側ではなく内側の pcall に捕捉されます。これにより、フォールバック戦略を実装できます。
local function tryPrimary()
error("primary failed")
end
local function tryFallback()
return "fallback result"
end
local ok, result = pcall(tryPrimary)
if not ok then
print("Primary failed:", result)
ok, result = pcall(tryFallback)
end
if ok then print("Got:", result) end -- fallback resultメソッドでの pcall
pcall 経由でメソッド(コロン構文)を呼び出すには、関数とオブジェクトを最初の引数として渡します。pcall(obj.method, obj, args...) のようにするか、クロージャーでラップします。
local obj = {
x = 10,
compute = function(self, n)
if n == 0 then error("zero divisor") end
return self.x / n
end
}
-- Pass method + self explicitly
local ok, v = pcall(obj.compute, obj, 2)
print(ok, v) -- true 5.0
-- Or use a closure
ok, v = pcall(function() return obj:compute(0) end)
print(ok, v) -- false ...zero divisorIO の安全性に pcall を使う
IO 操作を pcall でラップし、予期しない OS エラーを捕捉します。一貫した結果とエラーのペアを返すことで、呼び出し側が失敗に適切に対処できるようにします。
local function safeRead(path)
local ok, result = pcall(function()
local f = assert(io.open(path, "r"))
local content = f:read("a")
f:close()
return content
end)
if ok then return result
else return nil, result
end
end
local data, err = safeRead("config.txt")
if data then print("Read", #data, "bytes")
else print("Error:", err)
endpcall によるリトライパターン
pcall を使ってエラーを捕捉し、不安定な操作(ネットワーク要求やファイル書き込み)を最大 N 回まで再試行します。実際のコードでは、再試行の間にスリープするか、コルーチンを使用します。
local function retry(fn, maxAttempts)
local attempts = 0
while attempts < maxAttempts do
attempts = attempts + 1
local ok, result = pcall(fn)
if ok then
print("Succeeded on attempt", attempts)
return result
end
print("Attempt", attempts, "failed:", result)
end
error("all " .. maxAttempts .. " attempts failed")
end
local n = 0
retry(function()
n = n + 1
if n < 3 then error("not ready") end
return "done"
end, 5)pcall の結果をテーブルに保存する
ループ内で pcall を使用する場合は、後で分析できるように結果をテーブルに保存します。最初の失敗で停止せず、すべての項目を処理してエラーを収集したいバッチ処理で役立ちます。
local jobs = {10, -5, 25, 0, 16}
local results = {}
for _, n in ipairs(jobs) do
local ok, v = pcall(function()
if n < 0 then error("negative") end
return math.sqrt(n)
end)
results[#results+1] = {input=n, ok=ok, value=v}
end
for _, r in ipairs(results) do
if r.ok then
print(r.input, "->", string.format("%.3f", r.value))
else
print(r.input, "-> ERROR:", r.value)
end
endpcall と xpcall の比較
pcall はエラーを捕捉しますが、得られるのはエラー値だけです。xpcall ではメッセージハンドラー関数を指定でき、スタックがまだ保持されている間に実行されるため、スタックトレースを取得できます。トレースバックが必要な場合は xpcall を選択してください。
-- pcall: simple, no traceback
local ok1, err1 = pcall(function()
error("simple error")
end)
print(err1) -- only the error message
-- xpcall: with traceback handler
local ok2, err2 = xpcall(
function() error("traced error") end,
function(e) return debug.traceback(e, 2) end
)
print(err2) -- full stack tracepcall の戻り値規約
pcall を基盤として一貫した API を設計します。成功時は常に value を返し、失敗時は nil, errorMessage を返します。関数をこの方式で構成すれば、呼び出し側は常に何が返るかを把握できます。
local function loadJSON(path)
local ok, result = pcall(function()
local f = assert(io.open(path, "r"))
local text = f:read("a")
f:close()
-- Fake JSON parse for demo
return {data = text, path = path}
end)
if ok then return result
else return nil, result
end
end
local data, err = loadJSON("data.json")
if data then print("Loaded:", data.path)
else print("Failed:", err)
end理解度チェック
保護された関数が成功した場合、pcall は何を返しますか?
まとめ: pcall
まとめ:
pcall(f, ...)→true, results...またはfalse, err- 最初の戻り値を確認して成功か失敗かを判断します
- 成功時は true の後に複数の戻り値が続きます
- pcall のネスト: それぞれが独立して自身のエラーを捕捉します
- リトライパターン: 不安定な操作に対して pcall を使ったループを実行します
- スタックトレースが必要な場合は xpcall を使用します
よくある質問
「pcallによる保護付き呼び出し」レッスンは無料ですか?
はい。「pcallによる保護付き呼び出し」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Lua Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Lua Academyコースには全4レッスンが含まれています。
「pcallによる保護付き呼び出し」で何を学びますか?
pcallでエラーを安全に捕捉し、戻り値を解釈します。 ブラウザで直接実行するハンズオンコードでLua Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Lua Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのLua Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「pcallによる保護付き呼び出し」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このLua Academyレッスンでコードを書いて実行できますか?
はい。すべてのLua Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- error()関数
- pcallによる保護付き呼び出し
- xpcallとメッセージハンドラー
- 構造化エラーオブジェクト