Lua Academy · Oppitunti

error()-funktio

Nostakaa virheitä error()-funktiolla ja perehtykää virhetasoihin ja -viesteihin.

Oppitunti 1/412 vaihetta

error()-funktio on ilmainen Lua Academy-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Lua Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Lua Academy-kurssilla on yhteensä 4 oppituntia.

Virheiden aiheuttaminen

error(message, level) aiheuttaa Lua-virheen. Suoritus pysähtyy, ja virhe etenee kutsupinoa ylöspäin, kunnes pcall tai xpcall ottaa sen kiinni tai ohjelma päättyy. Viesti voi olla mikä tahansa arvo — merkkijono, taulukko tai luku.

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

Virhetasot

error()-funktion toinen argumentti määrittää, missä virhe ilmoitetaan. Taso 1 (oletus) osoittaa itse error()-kutsuun. Taso 2 osoittaa kutsujaan. Taso 0 ei lisää sijaintitietoja. Käyttäkää kirjastofunktioissa tasoa 2, jotta virhe kohdistuu käyttäjän koodiin.

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

Virhe taulukko-objektina

Taulukon välittäminen virhearvoksi antaa kutsujille mahdollisuuden tarkastella jäsenneltyjä virhetietoja, kuten virhekoodia, viestiä ja asiayhteyttä. Tämä on informatiivisempaa kuin pelkkä merkkijono ja mahdollistaa ohjelmallisen virheenkäsittelyn.

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() syntaktisena lyhenteenä

assert(v, msg) vastaa rakennetta if not v then error(msg, 2) end; return v, .... Se on idiomaattinen tapa tarkistaa esiehdot. Jos v on tosiarvoinen, assert palauttaa kaikki argumenttinsa (mikä on hyödyllistä kutsujen ketjuttamisessa).

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() verrattuna return nil,err-rakenteeseen

Virheen ilmoittamiseen on kaksi käytäntöä: error() (poikkeustyyli) tai return nil, msg (funktionaalinen tyyli). Käyttäkää error()-funktiota aidosti odottamattomissa tilanteissa (ohjelmointivirheet ja sopimusrikkomukset). Käyttäkää nil, msg -palautusta odotettavissa oleviin epäonnistumisiin (tiedostoa ei löydy, verkkoyhteyden aikakatkaisu).

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

Virheet metametodeissa

Virheitä voi aiheuttaa metametodien sisällä. Jos metametodi aiheuttaa virheen, se etenee operaation käynnistäneeseen koodiin (kuten aritmeettiseen lausekkeeseen). Suojatkaa metametodit aina virheellisiltä syötteiltä.

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)

Mukautetut virhetyypit

Luo apufunktio tyypitettyjen virheolioiden muodostamista varten. Lisää tyyppitunniste, jotta kutsuja voi erottaa erityyppiset virheet toisistaan ja käsitellä kutakin asianmukaisesti.

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

Virheiden välittäminen

Kun funktio kutsuu toista funktiota ja siinä tapahtuu virhe, virhe välittyy automaattisesti kutsupinoa ylöspäin. Virhettä ei tarvitse heittää uudelleen — älkää vain ottako sitä kiinni. Ottakaa virheet kiinni sillä tasolla, jolla voitte käsitellä tai raportoida ne mielekkäästi.

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

Kutsupino debug.traceback-funktiolla

Pelkkä error() antaa yhden rivin kontekstia. Saatte koko kutsupinon jäljityksen käyttämällä debug.traceback(msg)-funktiota virhearvona. Näin tehdään yleensä xpcall-käsittelijässä.

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

Virheiden heittäminen uudelleen

Joskus virhe otetaan kiinni kontekstin lisäämiseksi ja heitetään sitten uudelleen. Käyttäkää merkkijonomuotoista virhettä uudelleen heitettäessä error(err, 0) (taso 0), jotta jo muotoiltuun viestiin ei lisätä uutta sijaintietuliitettä.

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)

Pikakertaus

Mitä taso 2 tarkoittaa kutsussa error("msg", 2)?

Kertaus: error()

Yhteenveto:

  • error(msg, level) — nostaa virheen; taso 2 kohdistaa virheen kutsujaan
  • Käyttäkää tauluja rakenteisille virheille, jotka sisältävät tyypin ja kontekstin
  • assert(v, msg) — idiomattinen esiehdon tarkistus
  • Käyttäkää error()-funktiota ohjelmointivirheisiin; palauttakaa odotettavissa olevissa epäonnistumisissa nil+err
  • Heittäkää virhe uudelleen kutsulla error(err, 0), jotta viestin muotoilu säilyy
Aloita maksutta

Opi Lua tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
40
Oppitunnit
159

Usein kysytyt kysymykset

Onko oppitunti ”error()-funktio” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Lua Academy-oppimispolun 3 oppituntia, myös oppitunnin “error()-funktio”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Lua Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”error()-funktio”?

Nostakaa virheitä error()-funktiolla ja perehtykää virhetasoihin ja -viesteihin. Harjoittelet Lua Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni Lua Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin Lua Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.

Kuinka kauan ”error()-funktio”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä Lua Academy-oppitunnilla?

Kyllä. Jokainen Lua Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. error()-funktio
  2. Suojatut kutsut pcall-funktiolla
  3. xpcall ja viestinkäsittelijät
  4. Rakenteiset virheoliot
← Takaisin: Lua Academy