0Pricing
Lua Academy · Урок

Функция error()

Вызывайте ошибки с помощью error() и изучайте уровни и сообщения ошибок.

«Функция error()» — бесплатный урок Lua Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Lua Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Lua Academy содержит 4 уроков всего.

Вызов ошибок

error(message, level) вызывает ошибку Lua. Выполнение останавливается, а ошибка распространяется вверх по стеку вызовов, пока её не перехватит pcall или xpcall либо пока она не завершит программу. Сообщением может быть любое значение: строка, таблица или число.

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

Уровни ошибок

Второй аргумент error() определяет, где указывается источник ошибки. Уровень 1 (по умолчанию) указывает на сам вызов error(). Уровень 2 указывает на вызывающий код. Уровень 0 не добавляет информацию о позиции. В библиотечных функциях используйте уровень 2, чтобы источником ошибки считался код пользователя.

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

Ошибка с объектами-таблицами

Передача таблицы в качестве значения ошибки позволяет вызывающему коду изучить структурированную информацию: код ошибки, сообщение и контекст. Это информативнее обычной строки и позволяет обрабатывать ошибки программно.

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() как сокращённая запись

assert(v, msg) эквивалентна конструкции if not v then error(msg, 2) end; return v, .... Это идиоматичный способ проверять предусловия. Если v имеет истинное значение, assert возвращает все свои аргументы, что удобно для объединения вызовов в цепочку.

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

Существует два соглашения для сообщения о сбое: error() в стиле исключений или return nil, msg в функциональном стиле. Используйте error() для действительно неожиданных ситуаций: ошибок программирования и нарушений контрактов. Для ожидаемых сбоев, например отсутствия файла или тайм-аута сети, используйте nil, msg.

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

Ошибки в метаметодах

Ошибки могут возникать внутри метаметодов. Если метаметод вызывает ошибку, она распространяется в код, инициировавший операцию, например арифметическое выражение. Всегда проверяйте в метаметодах входные данные на недопустимые значения.

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)

Пользовательские типы ошибок

Создайте вспомогательную функцию для создания типизированных объектов ошибок. Добавьте тег типа, чтобы вызывающий код мог различать разные виды ошибок и обрабатывать каждую подходящим образом.

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

Распространение ошибок

Когда одна функция вызывает другую, в которой возникает ошибка, ошибка автоматически распространяется вверх по стеку вызовов. Повторно возбуждать её не нужно — просто не перехватывайте её. Перехватывайте ошибки только на том уровне, где Вы можете осмысленно их обработать или сообщить о них.

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

Трассировка стека с помощью debug.traceback

Обычный вызов error() предоставляет одну строку контекста. Для получения полной трассировки стека используйте debug.traceback(msg) в качестве значения ошибки. Обычно это делается в обработчике 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

Повторное возбуждение ошибок

Иногда ошибку перехватывают, чтобы добавить контекст, а затем возбуждают повторно. Используйте error(err, 0) (уровень 0) при повторном возбуждении строковой ошибки, чтобы не добавлять ещё один префикс с расположением к уже отформатированному сообщению.

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)

Быстрая проверка

Что означает уровень 2 в error("msg", 2)?

Итоги: error()

Краткое содержание:

  • error(msg, level) — возбуждает ошибку; уровень 2 указывает на вызывающий код
  • Используйте таблицы для структурированных ошибок с типом и контекстом
  • assert(v, msg) — идиоматичная проверка предусловия
  • Используйте error() для ошибок в программе; для ожидаемых сбоев возвращайте nil+err
  • Повторно возбуждайте ошибку с помощью error(err, 0), чтобы сохранить формат сообщения

Часто задаваемые вопросы

Урок «Функция error()» бесплатный?

Да — полный текст урока «Функция error()» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Lua Academy, подпишись на CoddyKit PRO. Курс Lua Academy содержит 4 уроков всего.

Чему я научусь в уроке «Функция error()»?

Вызывайте ошибки с помощью error() и изучайте уровни и сообщения ошибок. Ты практикуешь Lua Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Lua Academy?

Предыдущий опыт не требуется. Lua Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Функция error()»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Lua Academy?

Да. Каждый урок Lua Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Функция error()
  2. Защищённые вызовы с pcall
  3. xpcall и обработчики сообщений
  4. Структурированные объекты ошибок
← Назад к Lua Academy