0Pricing
Lua Academy · Pelajaran

Objek Galat Terstruktur

Gunakan tabel sebagai objek galat untuk menyampaikan tipe dan konteks.

Objek Galat Terstruktur adalah pelajaran Lua Academy gratis di CoddyKit. Ini adalah pelajaran 4 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Lua Academy, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Lua Academy mencakup 4 pelajaran total.

Mengapa Error Terstruktur?

Error berupa string biasa sulit ditangani secara terprogram. Objek error terstruktur (tabel) membawa informasi jenis dan data konteks, serta dapat diperiksa dan ditindaklanjuti oleh pemanggil. Ini memungkinkan pengalihan berdasarkan error tanpa mengurai string.

-- 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"
})

Pola Konstruktor Error

Buat fungsi pabrik error untuk setiap jenis error. Pabrik tersebut membangun tabel dengan bidang yang konsisten: jenis, pesan, dan konteks yang relevan. Metamethod __tostring membuat error tercetak dengan baik.

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 Error

Setelah menangkap error, periksa apakah nilainya berupa tabel dengan bidang jenis yang dikenal. Dengan demikian, Anda dapat mengalihkan strategi pemulihan yang berbeda berdasarkan jenis error tanpa bergantung pada pencocokan pola string.

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 Error

Simulasikan hierarki error dengan memeriksa bidang is_a atau menggunakan metatabel. Jenis error turunan mewarisi bidang jenis induknya dan dapat diperlakukan sebagai induknya oleh kode yang tidak memerlukan perincian 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

Membungkus Error

Saat menangkap dan melempar ulang error, bungkus error asli untuk menambahkan konteks tanpa kehilangannya. Pembungkus tersebut memiliki jenisnya sendiri dan membawa error asli sebagai penyebab.

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

Kode Error vs Jenis Error

Dua konvensi umum: kode error (numerik, seperti kode status HTTP) dan string jenis error (nama semantik). Kode error mudah dibandingkan secara numerik; string jenis menjelaskan maknanya sendiri. Banyak sistem menggunakan keduanya.

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"))

Stack Error (Rantai Penyebab)

Jika suatu error disebabkan oleh error lain, rangkailah keduanya. Ini memberikan gambaran lengkap tentang hal yang salah pada setiap lapisan aplikasi. Lepaskan pembungkus rantai tersebut untuk mencatat atau menampilkan keseluruhan riwayat error.

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

Error dalam Konteks Callback

Saat error terjadi di dalam callback (handler peristiwa, iterator), error tersebut merambat ke pemanggil callback. Gunakan pcall untuk menangkapnya dan melaporkannya dengan konteks callback 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 Detail Error

Buat helper yang mencetak objek error dengan cara terstruktur dan mudah dibaca—menangani error berupa string maupun tabel. Ini berguna di batas aplikasi tempat error dicatat atau ditampilkan 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

Assertion dengan Error Terstruktur

Buat assertT (assert dengan error bertipe) yang menghasilkan error terstruktur, bukan string biasa. Ini memudahkan pemanggil menguji jenis error 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

Pemeriksaan Singkat

Apa keunggulan utama meneruskan tabel ke error() alih-alih string?

Rangkuman: Error Terstruktur

Rangkuman:

  • Teruskan tabel ke error() untuk error yang terstruktur dan dapat diperiksa
  • Sertakan: jenis, pesan, dan bidang konteks yang relevan
  • Tambahkan __tostring untuk keluaran yang mudah dibaca
  • Bungkus error untuk menambahkan konteks tanpa kehilangan penyebabnya
  • Pengalihan berdasarkan jenis dalam handler: periksa err.type, bukan pola string

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Objek Galat Terstruktur” gratis?

Ya — teks lengkap “Objek Galat Terstruktur” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Lua Academy, upgrade ke CoddyKit PRO. Kursus Lua Academy mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Objek Galat Terstruktur”?

Gunakan tabel sebagai objek galat untuk menyampaikan tipe dan konteks. Kamu berlatih Lua Academy dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Lua Academy?

Tidak diperlukan pengalaman sebelumnya. Lua Academy di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 4 dari 4.

Berapa lama pelajaran “Objek Galat Terstruktur” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Lua Academy ini?

Ya. Setiap pelajaran Lua Academy menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. Fungsi error()
  2. Pemanggilan Terlindungi dengan pcall
  3. xpcall dan Penangan Pesan
  4. Objek Galat Terstruktur
← Kembali ke Lua Academy