Lua Academy · Pelajaran

Objek Ralat Berstruktur

Luluskan jadual sebagai objek ralat untuk menyampaikan jenis dan konteks.

Pelajaran 4 daripada 412 langkah

Objek Ralat Berstruktur ialah pelajaran Lua Academy percuma di CoddyKit. Ini ialah pelajaran 4 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Lua Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Lua Academy merangkumi sejumlah 4 pelajaran.

Mengapa Ralat Berstruktur?

Ralat rentetan biasa sukar dikendalikan secara terprogram. Objek ralat berstruktur (jadual) membawa maklumat jenis dan data konteks, serta boleh diperiksa dan diambil tindakan oleh pemanggil. Ini membolehkan penghantaran berasaskan ralat tanpa menghuraikan rentetan.

-- Plain string: hard to handle programmatically
error("database error: connection refused")

-- Structured: type + data
error({
  type = "DatabaseError",
  code = "CONN_REFUSED",
  host = "localhost",
  port = 5432,
  message = "connection refused"
})

Corak Pembina Ralat

Cipta fungsi kilang ralat untuk setiap jenis ralat. Kilang itu membina jadual dengan medan yang konsisten: jenis, mesej dan sebarang konteks yang berkaitan. Kaedah metam __tostring menjadikan ralat dicetak dengan kemas.

local ErrorMT = {__tostring = function(e)
  return string.format("[%s] %s", e.type, e.message)
end}

local function makeError(errType, msg, data)
  local e = {type=errType, message=msg}
  if data then for k,v in pairs(data) do e[k]=v end end
  return setmetatable(e, ErrorMT)
end

local E = {
  notFound = function(name) return makeError("NOT_FOUND","not found: "..name,{name=name}) end,
  badInput = function(msg,field) return makeError("BAD_INPUT",msg,{field=field}) end,
}

local ok, err = pcall(error, E.notFound("user:42"))
print(tostring(err))   -- [NOT_FOUND] not found: user:42

Pemeriksaan Jenis Objek Ralat

Selepas menangkap ralat, periksa sama ada ralat itu ialah jadual dengan medan jenis yang diketahui. Ini membolehkan Anda menghantar kepada strategi pemulihan yang berbeza berdasarkan jenis ralat tanpa bergantung pada pemadanan corak rentetan.

local function handleRequest(fn)
  local ok, err = pcall(fn)
  if ok then return true end
  if type(err) == "table" then
    if err.type == "NOT_FOUND" then
      print("404: " .. err.message)
    elseif err.type == "BAD_INPUT" then
      print("400: " .. err.message .. " (field: " .. (err.field or "?") .. ")")
    else
      print("500: unhandled error: " .. tostring(err))
    end
  else
    print("500: " .. tostring(err))
  end
  return false
end

Hierarki Ralat

Simulasikan hierarki ralat dengan memeriksa medan is_a atau menggunakan jadual meta. Jenis ralat anak mewarisi medan jenis induk dan boleh dianggap sebagai induk oleh kod yang tidak memerlukan butiran khusus.

local function isError(e, errType)
  if type(e) ~= "table" then return false end
  return e.type == errType or e.parentType == errType
end

local function makeDbError(code, msg)
  return {type="DbError:"..code, parentType="DbError", code=code, message=msg}
end

local err = makeDbError("TIMEOUT","query timed out")
print(isError(err, "DbError"))          -- true
print(isError(err, "DbError:TIMEOUT"))  -- true
print(isError(err, "NetworkError"))     -- false

Membalut Ralat

Apabila menangkap dan menjana semula ralat, balut ralat asal untuk menambahkan konteks tanpa kehilangannya. Pembalut itu mempunyai jenisnya sendiri dan membawa ralat asal sebagai punca.

local function wrapError(msg, cause)
  return {
    type = "WrappedError",
    message = msg,
    cause = cause,
  }
end

local function loadConfig(path)
  local ok, err = pcall(function()
    local f = assert(io.open(path,"r"))
    local content = f:read("a")
    f:close()
    return content
  end)
  if not ok then
    error(wrapError("failed to load config: "..path, err))
  end
end

local ok2, e = pcall(loadConfig, "missing.cfg")
if not ok2 then
  print(e.message)
  print("Caused by:", tostring(e.cause))
end

Kod Ralat berbanding Jenis Ralat

Dua konvensyen yang biasa ialah: kod ralat (berangka, seperti kod status HTTP) dan rentetan jenis ralat (nama semantik). Kod ralat mudah dibandingkan secara berangka; rentetan jenis menerangkan maksudnya sendiri. Banyak sistem menggunakan kedua-duanya.

local STATUS = {OK=200, NOT_FOUND=404, SERVER_ERROR=500, BAD_REQUEST=400}

local function makeStatusError(status, msg)
  return {status=status, message=msg, type="HTTPError"}
end

local function handleError(e)
  if e.status == STATUS.NOT_FOUND then
    print("Resource not found:", e.message)
  elseif e.status >= 500 then
    print("Server error:", e.message)
  else
    print("Error", e.status, e.message)
  end
end

handleError(makeStatusError(404, "user not found"))

Tindanan Ralat (Rantaian Punca)

Apabila satu ralat disebabkan oleh ralat lain, rantai kedua-duanya. Ini memberikan gambaran penuh tentang perkara yang berlaku pada setiap lapisan aplikasi. Nyahbalut rantaian itu untuk mencatat atau memaparkan keseluruhan kisah ralat.

local function unwindCause(e, depth)
  depth = depth or 0
  local pad = string.rep("  ", depth)
  if type(e) == "table" then
    print(pad .. (e.type or "Error") .. ": " .. (e.message or "?"))
    if e.cause then unwindCause(e.cause, depth+1) end
  else
    print(pad .. tostring(e))
  end
end

local inner = {type="IoError", message="permission denied"}
local outer = {type="ConfigError", message="cannot load config", cause=inner}
unwindCause(outer)
-- ConfigError: cannot load config
--   IoError: permission denied

Ralat dalam Konteks Panggilan Balik

Apabila ralat berlaku di dalam panggilan balik (pengendali peristiwa, lelar), ralat itu tersebar kepada pemanggil panggilan balik. Gunakan pcall untuk menangkapnya dan melaporkannya bersama konteks tentang panggilan balik yang gagal.

local function runCallbacks(callbacks, data)
  local errors = {}
  for name, fn in pairs(callbacks) do
    local ok, err = pcall(fn, data)
    if not ok then
      errors[#errors+1] = {callback=name, error=err}
    end
  end
  return errors
end

local cbs = {
  validate = function(d) assert(d.name, "name required") end,
  transform = function(d) d.name = d.name:upper() end,
}

local errs = runCallbacks(cbs, {})
for _, e in ipairs(errs) do
  print(e.callback, "->", e.error)
end

Mencetak Butiran Ralat

Pembantu yang mencetak objek ralat dengan cara yang berstruktur dan mudah dibaca — serta mengendalikan ralat rentetan dan jadual. Ini berguna pada sempadan aplikasi apabila ralat dicatat atau dipaparkan kepada pengguna.

local function printError(err, prefix)
  prefix = prefix or "Error"
  if type(err) ~= "table" then
    print(prefix .. ": " .. tostring(err))
    return
  end
  print(prefix .. " [" .. (err.type or "unknown") .. "]")
  print("  Message: " .. (err.message or "?"))
  for k, v in pairs(err) do
    if k ~= "type" and k ~= "message" and k ~= "cause" then
      print("  " .. k .. ": " .. tostring(v))
    end
  end
  if err.cause then printError(err.cause, "  Caused by") end
end

Pengesahan dengan Ralat Berstruktur

Cipta assertT (assert dengan ralat berjenis) yang menghasilkan ralat berstruktur dan bukannya rentetan biasa. Ini memudahkan pemanggil menguji jenis ralat tertentu.

local function assertT(cond, errType, msg, data)
  if not cond then
    local e = {type=errType, message=msg}
    if data then for k,v in pairs(data) do e[k]=v end end
    error(e, 2)
  end
  return cond
end

local function createUser(name, age)
  assertT(type(name)=="string", "BAD_INPUT", "name must be string", {field="name"})
  assertT(age >= 0 and age <= 150, "BAD_INPUT", "invalid age", {field="age", value=age})
  return {name=name, age=age}
end

local ok, err = pcall(createUser, "Alice", -5)
if not ok then print(err.type, err.field, err.value) end

Semakan Pantas

Apakah kelebihan utama menghantar jadual kepada error() berbanding rentetan?

Imbas Kembali: Ralat Berstruktur

Ringkasan:

  • Hantarkan jadual kepada error() untuk mendapatkan ralat yang berstruktur dan boleh diperiksa
  • Sertakan: jenis, mesej dan medan konteks yang berkaitan
  • Tambahkan __tostring untuk keluaran yang mudah dibaca
  • Balut ralat untuk menambahkan konteks tanpa kehilangan punca
  • Penghantaran mengikut jenis dalam pengendali: periksa err.type, bukan corak rentetan
Percuma untuk bermula

Pelajari Lua dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
40
Pelajaran
159

Soalan Lazim

Adakah pelajaran “Objek Ralat Berstruktur” percuma?

Ya — sebanyak 3 pelajaran dalam laluan pembelajaran Lua Academy, termasuk “Objek Ralat Berstruktur”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus Lua Academy merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “Objek Ralat Berstruktur”?

Luluskan jadual sebagai objek ralat untuk menyampaikan jenis dan konteks. Anda berlatih Lua Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Lua Academy?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Lua Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 4 daripada 4.

Berapa lamakah pelajaran “Objek Ralat Berstruktur” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Lua Academy ini?

Ya. Setiap pelajaran Lua Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. Fungsi error()
  2. Panggilan Terlindung dengan pcall
  3. xpcall dan Pengendali Mesej
  4. Objek Ralat Berstruktur
← Kembali ke Lua Academy