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.opentonumber
返回 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

→ 下一篇 协程