Функция 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)
endassert() как сокращённая запись
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 stringerror() и 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 — локальная установка не требуется.
Все уроки этого курса
- Функция error()
- Защищённые вызовы с pcall
- xpcall и обработчики сообщений
- Структурированные объекты ошибок