0Pricing
Lua Academy · บทเรียน

การเรียกใช้แบบป้องกันด้วย 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 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 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
end

pcall เทียบกับ 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ฟังก์ชัน error()
  2. การเรียกใช้แบบป้องกันด้วย pcall
  3. xpcall และตัวจัดการข้อความ
  4. ออบเจกต์ข้อผิดพลาดแบบมีโครงสร้าง
← กลับไปที่ Lua Academy