error 抛错
local function divide(a, b)
if b == 0 then error("除以 0") end
return a / b
end
divide(10, 0)
-- lua: file.lua:2: 除以 0
-- stack traceback: ...
未捕获的 error 让程序退出。
pcall:捕获错误
local ok, err = pcall(divide, 10, 0)
if ok then
print("结果", err) -- 没错时 err 是返回值
else
print("出错", err) -- "file.lua:2: 除以 0"
end
pcall(fn, args...) 等于 try-catch:
- 成功:
true, 返回值... - 失败:
false, error_value
xpcall:带处理器
local function handler(err)
return debug.traceback(err, 2)
end
local ok, info = xpcall(divide, handler, 10, 0)
print(info)
-- file.lua:2: 除以 0
-- stack traceback:
-- [C]: in function 'error'
-- file.lua:2: in function 'divide'
-- ...
handler 在错误发生时调用——拿到完整堆栈。生产代码几乎一定用 xpcall(pcall 拿不到栈)。
error 抛任何东西
error("string error")
error({code = 500, msg = "server error"}) -- 表也行
error(42) -- 数字也行
最常见还是字符串。
error(msg, level):
level=1默认,报错位置 = error() 调用处level=2报错位置 = 调用 error() 的函数的调用处(库函数常用)level=0不加位置信息
local function check(cond, msg)
if not cond then
error(msg, 2) -- 把锅推给调用方
end
end
assert:简洁的断言
local function divide(a, b)
assert(b ~= 0, "除以 0")
return a / b
end
assert(cond, msg) = if not cond then error(msg) end。
Lua 库大量用这个模式:
local ok, err = io.open("nofile.txt") -- 失败返回 nil, errmsg
local file = assert(io.open("nofile.txt")) -- 失败时打印 errmsg
错误处理风格选择
| 风格 | 例 |
|---|---|
| 抛错 | error("...") / assert(...) |
返回 nil, errmsg |
io.open、tonumber |
返回 false, errmsg |
部分库函数 |
Lua 习惯优先"返回 nil"——除非真的异常状况才抛错。和 Go 的"返回 error" 风格一致。
-- ❌ Java 风格
local file
local ok, err = pcall(function() file = io.open("nofile") end)
-- ✅ Lua 风格
local file, err = io.open("nofile")
if not file then return nil, err end
try / finally(5.4 的 )
5.4 引入 to-be-closed 变量:
do
local f <close> = io.open("data.txt", "w")
f:write("hello")
-- 离开作用域时自动关闭(哪怕中间抛错)
end
需要对象的 metatable 有 __close 元方法。io.open 返回的 file 默认支持。
5.1 / LuaJIT 没这特性——用 pcall 包一层:
local f = io.open("data.txt", "w")
local ok, err = pcall(function() f:write("hello") end)
f:close()
if not ok then error(err) end
错误栈传播
local function deep()
error("oops")
end
local function shallow()
return deep() -- 不接 / 不 pcall → 自动向上传播
end
local ok, err = pcall(shallow) -- 在这里被捕获
不要乱吞错误
-- ❌ 灾难
local ok = pcall(some_function)
if not ok then end -- 静默吃了
至少打印或上报:
local ok, err = xpcall(some_function, debug.traceback)
if not ok then
print("ERROR:", err)
end
→ 下一篇 协程