การเรียกใช้แบบป้องกันด้วย pcall
ดักจับข้อผิดพลาดอย่างปลอดภัยด้วย pcall และแปลความหมายค่าที่ส่งคืน
การเรียกใช้แบบป้องกันด้วย pcall เป็นบทเรียน Lua Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน 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
endการซ้อน pcall
สามารถซ้อนการเรียก 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 resultpcall กับเมธอด
หากต้องการเรียกเมธอด (ไวยากรณ์แบบโคลอน) ผ่าน 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 divisorใช้ pcall เพื่อความปลอดภัยของ IO
ห่อการดำเนินการ 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)
endรูปแบบการลองใหม่ด้วย pcall
ลองดำเนินการที่ไม่แน่นอน เช่น คำขอเครือข่ายหรือการเขียนไฟล์ ได้สูงสุด N ครั้ง โดยใช้ pcall เพื่อดักจับข้อผิดพลาด ในโค้ดจริงควรเว้นช่วงระหว่างการลองใหม่ (หรือใช้โครูทีน)
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 traceรูปแบบการคืนค่าของ pcall
ใช้ 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” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Lua Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Lua Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การเรียกใช้แบบป้องกันด้วย pcall”
ดักจับข้อผิดพลาดอย่างปลอดภัยด้วย pcall และแปลความหมายค่าที่ส่งคืน คุณปฏิบัติ Lua Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Lua Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Lua Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “การเรียกใช้แบบป้องกันด้วย pcall” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Lua Academy นี้ได้ไหม
ได้ บทเรียน Lua Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ฟังก์ชัน error()
- การเรียกใช้แบบป้องกันด้วย pcall
- xpcall และตัวจัดการข้อความ
- ออบเจกต์ข้อผิดพลาดแบบมีโครงสร้าง