On this page

Lua 错误处理

Lua 错误处理全面指南

Lua 提供了灵活的错误处理机制,帮助开发者编写健壮的程序。以下是 Lua 错误处理的完整介绍:

1. 基本错误处理

抛出错误

-- 使用error函数抛出错误
local function divide(a, b)
    if b == 0 then
        error("除数不能为零", 2)  -- 第二个参数表示调用层级
    end
    return a / b
end

捕获错误

-- 使用pcall保护调用
local success, result = pcall(function()
    return divide(10, 0)
end)

if not success then
    print("发生错误:", result)
end

2. xpcall 与错误处理函数

-- 自定义错误处理函数
local function errorHandler(err)
    local msg = "错误: " .. tostring(err) .. "\n"
    msg = msg .. debug.traceback()
    logToFile(msg)  -- 记录到日志文件
    return msg
end

-- 使用xpcall
local success, result = xpcall(
    function() return riskyOperation() end,
    errorHandler
)

3. assert 断言

local function openConfig(filename)
    local file = io.open(filename, "r")
    assert(file, "无法打开配置文件: " .. filename)
    return file
end

-- 使用
local ok, err = pcall(function()
    openConfig("missing.txt")
end)
if not ok then print(err) end

4. 错误级别与调用栈

Lua 错误包含调用栈信息:

function a() error("test error") end
function b() a() end
function c() b() end

local ok, err = pcall(c)
if not ok then
    print(debug.traceback(err))
end

5. 常见错误模式

返回错误码

function readFile(path)
    local file, err = io.open(path, "r")
    if not file then
        return nil, err
    end
    local content = file:read("*a")
    file:close()
    return content
end

-- 使用
local content, err = readFile("nonexistent.txt")
if not content then print("错误:", err) end

错误对象模式

local function makeError(code, message)
    return {
        code = code,
        message = message,
        timestamp = os.time(),
        __tostring = function(self)
            return string.format("[%d] %s (%s)", 
                self.code, self.message, os.date("%c", self.timestamp))
        end
    }
end

local function process(data)
    if not data then
        error(makeError(1001, "无效输入数据"))
    end
    -- 处理逻辑
end

6. 协程错误处理

local co = coroutine.create(function()
    error("协程内部错误")
end)

local ok, err = coroutine.resume(co)
if not ok then
    print("协程错误:", err)
    print(debug.traceback(co))
end

7. 资源清理模式

finally 模拟

local function with(resource, func)
    local ok, err = pcall(func, resource)
    if resource.close then resource:close() end
    if not ok then error(err) end
end

-- 使用
with(io.open("data.txt", "r"), function(file)
    local data = file:read("*a")
    process(data)
end)

8. 调试技巧

获取详细错误信息

function verboseError(err)
    local msg = "ERROR: " .. tostring(err) .. "\n"
    msg = msg .. "Stack Traceback:\n"
    msg = msg .. debug.traceback() .. "\n"
    
    -- 添加局部变量信息
    local level = 2
    while true do
        local name, value = debug.getlocal(level, 1)
        if not name then break end
        msg = msg .. string.format("L%d: %s = %s\n", 
              level-1, name, tostring(value))
        level = level + 1
    end
    
    return msg
end

9. 最佳实践

  1. 区分预期错误与程序错误

    • 预期错误(如文件不存在)应返回错误码
    • 程序错误(如逻辑错误)应抛出错误
  2. 错误信息规范化

    function newError(code, msg, details)
        return {
            code = code,
            message = msg,
            details = details,
            timestamp = os.time(),
            stack = debug.traceback()
        }
    end
    
  3. 错误处理层次化

    • 底层函数返回原始错误
    • 中层函数添加上下文
    • 顶层处理用户友好的错误消息
  4. 日志记录

    function logError(err)
        local logEntry = string.format("[%s] %s\n%s\n",
            os.date("%Y-%m-%d %H:%M:%S"),
            tostring(err),
            debug.traceback())
           
        -- 写入日志文件
        local logFile = io.open("error.log", "a")
        if logFile then
            logFile:write(logEntry)
            logFile:close()
        end
    end
    

Lua 的错误处理机制虽然简单,但结合调试库和良好的编程实践,可以构建出健壮的应用程序。关键是根据不同场景选择合适的错误处理策略。