error() 函数
使用 error() 抛出错误,并理解错误级别和错误消息。
error() 函数 是 CoddyKit 上的免费 Lua Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 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 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)快速检查
error("msg", 2) 中的级别 2 表示什么?
回顾:error()
总结:
error(msg, level)— 抛出错误;级别 2 将责任归于调用方- 使用表表示包含类型和上下文的结构化错误
assert(v, msg)— 符合惯用写法的前置条件检查- 对于程序缺陷使用
error();对于预期失败返回 nil+err - 使用
error(err, 0)重新抛出,以保留消息格式
常见问题解答
「error() 函数」课时是免费的吗?
是的 — 「error() 函数」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Lua Academy 课程的其余内容,请升级到 CoddyKit PRO。 Lua Academy 课程共包含 4 节课。
「error() 函数」这节课中我会学到什么?
使用 error() 抛出错误,并理解错误级别和错误消息。 你通过在浏览器中直接运行的动手代码来练习 Lua Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Lua Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Lua Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「error() 函数」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Lua Academy 课中编写并运行代码吗?
能。每节 Lua Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- error() 函数
- 使用 pcall 进行受保护调用
- xpcall 和消息处理器
- 结构化错误对象