0Pricing
Lua Academy · Lektion

Strukturierte Fehlerobjekte

Übergeben Sie Tabellen als Fehlerobjekte, um Typ und Kontext zu übermitteln

Strukturierte Fehlerobjekte ist eine kostenlose Lua Academy-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Lua Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Lua Academy-Kurs umfasst insgesamt 4 Lektionen.

Warum strukturierte Fehler?

Einfache String-Fehler lassen sich nur schwer programmgesteuert behandeln. Strukturierte Fehlerobjekte (Tabellen) enthalten Typinformationen und Kontextdaten und können von Aufrufern untersucht und verarbeitet werden. Dadurch wird eine fehlerbasierte Weiterleitung ohne Parsen von Zeichenketten möglich.

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

Muster für Fehlerkonstruktoren

Erstellen Sie für jeden Fehlertyp eine Fehlerfabrikfunktion. Die Fabrik erstellt eine Tabelle mit konsistenten Feldern: Typ, Nachricht und alle relevanten Kontextinformationen. Eine __tostring-Metamethode sorgt für eine übersichtliche Ausgabe des Fehlers.

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

Fehlerobjekte auf ihren Typ prüfen

Prüfen Sie nach dem Abfangen eines Fehlers, ob es sich um eine Tabelle mit einem bekannten Typfeld handelt. So können Sie je nach Fehlertyp unterschiedliche Wiederherstellungsstrategien auswählen, ohne auf Zeichenkettenmuster angewiesen zu sein.

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

Fehlerhierarchie

Simulieren Sie eine Fehlerhierarchie, indem Sie is_a-Felder prüfen oder Metatabellen verwenden. Untergeordnete Fehlertypen erben die Felder des übergeordneten Typs und können von Code, der keine Details benötigt, wie der übergeordnete Typ behandelt werden.

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

Fehler verpacken

Wenn Sie einen Fehler abfangen und erneut auslösen, verpacken Sie den ursprünglichen Fehler, um Kontext hinzuzufügen, ohne ihn zu verlieren. Der Wrapper hat einen eigenen Typ und enthält den ursprünglichen Fehler als Ursache.

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

Fehlercodes im Vergleich zu Fehlertypen

Zwei verbreitete Konventionen sind Fehlercodes (numerisch, etwa wie HTTP-Statuscodes) und Fehlertexten (semantische Bezeichnungen). Fehlercodes lassen sich leicht numerisch vergleichen, Typtexte sind selbsterklärend. Viele Systeme verwenden beides.

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

Fehlerstapel (Ursachenkette)

Wenn ein Fehler durch einen anderen verursacht wurde, verknüpfen Sie sie. So erhalten Sie ein vollständiges Bild davon, was auf den einzelnen Ebenen der Anwendung schiefgelaufen ist. Entpacken Sie die Kette, um die vollständige Fehlerursache zu protokollieren oder anzuzeigen.

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

Fehler im Callback-Kontext

Wenn innerhalb von Callbacks (Ereignishandlern, Iteratoren) Fehler auftreten, werden sie an den Aufrufer des Callbacks weitergegeben. Verwenden Sie pcall, um sie abzufangen und mit dem Kontext zu melden, welcher Callback fehlgeschlagen ist.

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

Fehlerdetails ausgeben

Eine Hilfsfunktion, die ein Fehlerobjekt strukturiert und verständlich ausgibt und dabei sowohl String- als auch Tabellenfehler behandelt. Das ist an Anwendungsgrenzen nützlich, an denen Fehler protokolliert oder Benutzern angezeigt werden.

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

Mit strukturierten Fehlern Zusicherungen prüfen

Erstellen Sie ein assertT (assert mit typisierten Fehlern), das einen strukturierten Fehler anstelle eines einfachen Strings auslöst. Dadurch können Aufrufer leicht auf bestimmte Fehlertypen testen.

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

Schnelltest

Was ist der wichtigste Vorteil, wenn Sie eine Tabelle statt eines Strings an error() übergeben?

Zusammenfassung: Strukturierte Fehler

Zusammenfassung:

  • Übergeben Sie Tabellen an error(), um strukturierte und untersuchbare Fehler zu erhalten
  • Fügen Sie Typ, Nachricht und relevante Kontextfelder hinzu
  • Fügen Sie __tostring für eine verständliche Ausgabe hinzu
  • Verpacken Sie Fehler, um Kontext hinzuzufügen, ohne die Ursache zu verlieren
  • Leiten Sie in Handlern anhand des Typs weiter: Prüfen Sie err.type statt Zeichenkettenmuster

Häufig gestellte Fragen

Ist die Lektion „Strukturierte Fehlerobjekte“ kostenlos?

Ja — der vollständige Text von „Strukturierte Fehlerobjekte“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Lua Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Lua Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Strukturierte Fehlerobjekte“?

Übergeben Sie Tabellen als Fehlerobjekte, um Typ und Kontext zu übermitteln Du übst Lua Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Lua Academy zu starten?

Keine Vorkenntnisse erforderlich. Lua Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.

Wie lange dauert die Lektion „Strukturierte Fehlerobjekte“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Lua Academy-Lektion Code schreiben und ausführen?

Ja. Jede Lua Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Die Funktion error()
  2. Geschützte Aufrufe mit pcall
  3. xpcall und Nachrichten-Handler
  4. Strukturierte Fehlerobjekte
← Zurück zu Lua Academy