0Pricing
Lua Academy · Lekcja

Funkcja error()

Proszę zgłaszać błędy za pomocą error() oraz poznać poziomy błędów i komunikaty.

Funkcja error() to bezpłatna lekcja Lua Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Lua Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Lua Academy zawiera 4 lekcji w sumie.

Zgłaszanie błędów

error(message, level) zgłasza błąd Lua. Wykonywanie zostaje zatrzymane, a błąd propaguje się w górę stosu wywołań, dopóki nie zostanie przechwycony przez pcall lub xpcall, albo dopóki nie zakończy działania programu. Komunikatem może być dowolna wartość — łańcuch znaków, tabela lub liczba.

local function divide(a, b)
  if b == 0 then
    error("division by zero")
  end
  return a / b
end

print(divide(10, 2))    -- 5.0
-- divide(10, 0)        -- ERROR: division by zero

Poziomy błędów

Drugi argument funkcji error() określa miejsce zgłoszenia błędu. Poziom 1 (domyślny) wskazuje samo wywołanie error(). Poziom 2 wskazuje kod wywołujący. Poziom 0 nie dodaje informacji o pozycji. W funkcjach bibliotecznych należy używać poziomu 2, aby wskazać kod użytkownika jako źródło problemu.

local function assertPositive(n, name)
  if n <= 0 then
    error((name or "value") .. " must be positive, got " .. n, 2)
    -- level 2: blame the caller, not this function
  end
  return n
end

local function compute(x)
  assertPositive(x, "x")   -- error points here if x <= 0
  return math.sqrt(x)
end

compute(-5)  -- error: "x must be positive, got -5" at compute() call

Błąd z obiektami typu table

Przekazanie tabeli jako wartości błędu umożliwia kodowi wywołującemu odczytanie ustrukturyzowanych informacji o błędzie: kodu błędu, komunikatu i kontekstu. Jest to bardziej informacyjne niż zwykły łańcuch znaków i umożliwia programową obsługę błędów.

local function openDB(host, port)
  if port < 1 or port > 65535 then
    error({code="INVALID_PORT", port=port,
           msg="port out of range: " .. port})
  end
  -- ... connect
  return {host=host, port=port}
end

local ok, err = pcall(openDB, "localhost", -1)
if not ok and type(err) == "table" then
  print("Code:", err.code)    -- INVALID_PORT
  print("Port:", err.port)    -- -1
  print("Msg:", err.msg)
end

assert() jako skrót składniowy

assert(v, msg) jest równoważne if not v then error(msg, 2) end; return v, .... Jest to idiomatyczny sposób sprawdzania warunków wstępnych. Jeśli v ma wartość prawdziwą, assert zwraca wszystkie swoje argumenty (co jest przydatne przy łączeniu wywołań).

local function sqrt(n)
  assert(type(n) == "number", "expected number, got " .. type(n))
  assert(n >= 0, "sqrt of negative: " .. n)
  return math.sqrt(n)
end

print(sqrt(16))    -- 4.0
print(sqrt(2))     -- 1.4142...
-- sqrt("hi")      -- ERROR: expected number, got string

error() a return nil,err

Istnieją dwie konwencje sygnalizowania niepowodzenia: error() (styl wyjątków) albo return nil, msg (styl funkcyjny). Używaj error() w przypadku rzeczywiście nieoczekiwanych sytuacji (błędów programistycznych, naruszenia kontraktu). Używaj nil, msg w przypadku oczekiwanych niepowodzeń (brak pliku, przekroczenie limitu czasu sieci).

-- Exception style (programming error)
local function mustExist(t, key)
  local v = t[key]
  if v == nil then error("required key missing: " .. key, 2) end
  return v
end

-- Functional style (expected failure)
local function findUser(id)
  -- ... database query
  return nil, "user not found"  -- expected: user may not exist
end

Błędy w metametodach

Błędy mogą być zgłaszane wewnątrz metametod. Jeśli metametoda zgłosi błąd, propaguje się on do kodu, który wywołał daną operację (na przykład wyrażenie arytmetyczne). W metametodach należy zawsze zabezpieczać się przed nieprawidłowymi danymi wejściowymi.

local SafeDiv = {}
SafeDiv.__index = SafeDiv

SafeDiv.__div = function(a, b)
  if b.value == 0 then
    error("SafeDiv: division by zero", 2)
  end
  return SafeDiv.new(a.value / b.value)
end

function SafeDiv.new(v)
  return setmetatable({value=v}, SafeDiv)
end

local a = SafeDiv.new(10)
local b = SafeDiv.new(0)
local ok, err = pcall(function() return a / b end)
print(ok, err)

Własne typy błędów

Proszę utworzyć funkcję pomocniczą do budowania obiektów błędów z typem. Należy dołączyć znacznik typu, aby kod wywołujący mógł rozróżniać różne rodzaje błędów i odpowiednio je obsługiwać.

local function newError(kind, msg, extra)
  return setmetatable(
    {kind=kind, message=msg, extra=extra},
    {__tostring = function(e)
      return "[" .. e.kind .. "] " .. e.message
    end}
  )
end

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

local ok, err = pcall(error, E.notFound("config.json"))
if not ok then print(err.kind, err.message) end

Propagacja błędów

Gdy funkcja wywołuje inną funkcję, która zgłasza błąd, błąd automatycznie propaguje się w górę stosu. Nie trzeba zgłaszać go ponownie — wystarczy go nie przechwytywać. Błędy należy przechwytywać dopiero na poziomie, na którym można je sensownie obsłużyć lub zgłosić.

local function step3() error("step3 failed") end
local function step2() step3() end
local function step1() step2() end

local ok, err = pcall(step1)
if not ok then
  -- err includes the source location
  print("Caught at top level:", err)
end
-- Error: input:1: step3 failed

Ślad stosu za pomocą debug.traceback

Zwykłe error() dostarcza jedną linię informacji kontekstowych. Aby uzyskać pełny ślad stosu, należy użyć debug.traceback(msg) jako wartości błędu. Zwykle robi się to w module obsługi xpcall.

local function buggy()
  local t = nil
  return t.field   -- nil indexing: error
end

local ok, err = xpcall(buggy, function(e)
  return debug.traceback(e, 2)  -- full stack trace
end)

if not ok then
  print(err)  -- full traceback
end

Ponowne zgłaszanie błędów

Czasami przechwytuje się błąd, aby dodać kontekst, a następnie zgłasza ponownie. Podczas ponownego zgłaszania błędu tekstowego należy użyć error(err, 0) (poziom 0), aby uniknąć dodania kolejnego prefiksu lokalizacji do już sformatowanego komunikatu.

local function loadAndParse(path)
  local ok, err = pcall(function()
    local f = io.open(path, "r")
    if not f then error("cannot open: " .. path) end
    local content = f:read("a")
    f:close()
    return content
  end)
  if not ok then
    error("loadAndParse failed: " .. err, 0)  -- re-raise with context
  end
end

local ok2, msg = pcall(loadAndParse, "missing.txt")
print(ok2, msg)

Szybkie sprawdzenie

Co oznacza poziom 2 w wywołaniu error("msg", 2)?

Podsumowanie: error()

Podsumowanie:

  • error(msg, level) — zgłasza błąd; poziom 2 wskazuje jako winowajcę kod wywołujący
  • Tabele służą do przechowywania ustrukturyzowanych błędów z typem i kontekstem
  • assert(v, msg) — idiomatyczne sprawdzanie warunku wstępnego
  • error() służy do błędów w kodzie; w przypadku oczekiwanych niepowodzeń należy zwracać nil+err
  • Błąd należy ponownie zgłaszać za pomocą error(err, 0), aby zachować format komunikatu

Często zadawane pytania

Czy lekcja „Funkcja error()” jest bezpłatna?

Tak — pełny tekst „Funkcja error()” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Lua Academy, przejdź na CoddyKit PRO. Kurs Lua Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Funkcja error()”?

Proszę zgłaszać błędy za pomocą error() oraz poznać poziomy błędów i komunikaty. Ćwiczysz Lua Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Lua Academy?

Nie wymagamy żadnego doświadczenia. Lua Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Funkcja error()”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Lua Academy?

Tak. Każda lekcja Lua Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Funkcja error()
  2. Wywołania chronione za pomocą pcall
  3. xpcall i programy obsługi komunikatów
  4. Strukturalne obiekty błędów
← Powrót do Lua Academy