Lua的错误处理基于"非局部跳转"(non-local goto)机制。当调用error()时,Lua会沿着调用栈向上查找pcall/xpcall保护。如果找到,就跳转到对应的错误处理器;如果没有找到保护,就终止程序。错误对象可以是任何类型,但通常是字符串或table。错误级别参数控制错误消息的显示位置:0(默认,在error位置)、1(在调用error的位置)、2(在调用者的位置)。
-- 基本错误抛出
function divide(a, b)
if b == 0 then
error("除数不能为0")
end
return a / b
end
-- divide(10, 0) -- 报错: 除数不能为0
-- 指定错误级别
function checkAge(age)
if age < 0 then
error("年龄不能为负数", 2) -- 2表示调用者的位置
end
end
-- 使用table作为错误对象
function createError(code, message)
return {
code = code,
message = message,
timestamp = os.time()
}
end
function validate(data)
if not data.name then
error(createError(400, "缺少name字段"))
end
if not data.age then
error(createError(400, "缺少age字段"))
end
end
-- 捕获table错误
local ok, err = pcall(validate, {name = "张三"})
if not ok then
print("错误代码:", err.code)
print("错误消息:", err.message)
print("时间戳:", os.date("%Y-%m-%d %H:%M:%S", err.timestamp))
end
-- assert用于条件检查
function openFile(filename)
local file = assert(io.open(filename, "r"), "文件打开失败: " .. filename)
return file
end
-- 等价于
function openFile(filename)
local file, err = io.open(filename, "r")
if not file then
error("文件打开失败: " .. filename)
end
return file
end
-- 使用示例
local file = assert(io.open("test.txt", "r"))
local content = file:read("*a")
file:close()
-- 检查参数
function setAge(age)
assert(type(age) == "number", "年龄必须是数字")
assert(age >= 0 and age <= 150, "年龄范围无效")
return age
end
-- pcall捕获错误
function riskyOperation()
error("出错了!")
end
local status, err = pcall(riskyOperation)
if status then
print("成功")
else
print("错误:", err)
end
-- 带参数的pcall
function divide(a, b)
if b == 0 then
error("除数不能为0")
end
return a / b
end
local status, result = pcall(divide, 10, 2)
if status then
print("结果:", result) -- 5
else
print("错误:", result)
end
local status, result = pcall(divide, 10, 0)
if status then
print("结果:", result)
else
print("错误:", result) -- 除数不能为0
end
-- 自定义错误处理函数
function errorHandler(err)
print("捕获到错误:", err)
print("调用栈:")
print(debug.traceback())
return "处理后的错误信息"
end
function riskyFunction()
local function inner()
error("内部错误")
end
inner()
end
local status, result = xpcall(riskyFunction, errorHandler)
print("状态:", status)
print("结果:", result)
-- 简化的错误处理
local status, result = xpcall(
function()
return divide(10, 0)
end,
function(err)
return "计算错误: " .. err
end
)
print(result)
-- 获取调用栈信息
function showStack()
print(debug.traceback())
end
function level3()
showStack()
end
function level2()
level3()
end
function level1()
level2()
end
level1()
-- 获取函数信息
function myFunction(a, b)
local info = debug.getinfo(1)
print("函数名:", info.name)
print("行号:", info.currentline)
print("源文件:", info.source)
end
myFunction(1, 2)
-- 获取局部变量
function inspectLocals()
local x = 10
local y = 20
local i = 1
while true do
local name, value = debug.getlocal(1, i)
if not name then break end
print(name, "=", value)
i = i + 1
end
end
inspectLocals()
-- 创建错误类
ValidationError = {}
ValidationError.__index = ValidationError
function ValidationError:new(message, field)
local obj = {
message = message,
field = field,
type = "ValidationError"
}
setmetatable(obj, ValidationError)
return obj
end
function ValidationError:__tostring()
return string.format("[%s] %s: %s", self.type, self.field, self.message)
end
-- 使用自定义错误
function validateUser(user)
if not user.name or user.name == "" then
error(ValidationError:new("名字不能为空", "name"))
end
if not user.age or user.age < 0 then
error(ValidationError:new("年龄无效", "age"))
end
end
-- 捕获并处理
local status, err = pcall(validateUser, {name = "", age = 25})
if not status then
if type(err) == "table" and err.type == "ValidationError" then
print("验证错误:", err.field, err.message)
else
print("其他错误:", err)
end
end
-- 重试机制
function retry(func, maxAttempts, delay)
local attempts = 0
while attempts < maxAttempts do
local status, result = pcall(func)
if status then
return true, result
end
attempts = attempts + 1
if attempts < maxAttempts then
print("重试 " .. attempts .. "/" .. maxAttempts)
if delay then
os.execute("sleep " .. delay)
end
end
end
return false, "达到最大重试次数"
end
-- 使用
local success, result = retry(
function()
-- 模拟可能失败的操作
if math.random() > 0.7 then
return "成功"
else
error("操作失败")
end
end,
3, -- 最多重试3次
1 -- 每次延迟1秒
)
if success then
print("操作成功:", result)
else
print("操作失败:", result)
end
-- 创建安全包装器
function safe(func)
return function(...)
local status, result = pcall(func, ...)
if status then
return result
else
print("错误:", result)
return nil
end
end
end
-- 使用
local safeDivide = safe(function(a, b)
if b == 0 then
error("除数不能为0")
end
return a / b
end)
print(safeDivide(10, 2)) -- 5
print(safeDivide(10, 0)) -- nil (打印错误信息)
-- 简单日志系统
Logger = {}
Logger.level = {
DEBUG = 1,
INFO = 2,
WARN = 3,
ERROR = 4
}
Logger.currentLevel = Logger.level.INFO
function Logger:log(level, message)
if level >= self.currentLevel then
local levelName = {"DEBUG", "INFO", "WARN", "ERROR"}
local timestamp = os.date("%Y-%m-%d %H:%M:%S")
print(string.format("[%s] [%s] %s", timestamp, levelName[level], message))
end
end
function Logger:debug(message)
self:log(self.level.DEBUG, message)
end
function Logger:info(message)
self:log(self.level.INFO, message)
end
function Logger:warn(message)
self:log(self.level.WARN, message)
end
function Logger:error(message)
self:log(self.level.ERROR, message)
end
-- 使用
Logger:info("程序启动")
Logger:warn("这是一个警告")
Logger:error("发生错误")
-- 保留原始错误信息
function wrapError(err, context)
return {
message = context,
cause = err,
traceback = debug.traceback()
}
end
function operation3()
error("底层错误")
end
function operation2()
local status, err = pcall(operation3)
if not status then
error(wrapError(err, "operation2失败"))
end
end
function operation1()
local status, err = pcall(operation2)
if not status then
error(wrapError(err, "operation1失败"))
end
end
-- 捕获并打印完整错误链
local status, err = pcall(operation1)
if not status then
local current = err
while current do
if type(current) == "table" then
print("错误:", current.message)
current = current.cause
else
print("原始错误:", current)
break
end
end
end
-- 条件断点
function conditionalBreak(condition, message)
if condition then
print("断点:", message)
print(debug.traceback())
io.read() -- 等待输入继续
end
end
-- 使用
for i = 1, 100 do
conditionalBreak(i == 50, "i达到50")
-- 其他代码
end
-- 变量监视
function watch(name, value)
print(string.format("变量 %s = %s", name, tostring(value)))
end
local x = 10
watch("x", x)
x = x + 5
watch("x", x)
-- 性能分析
function profile(func, ...)
local start = os.clock()
local result = {func(...)}
local elapsed = os.clock() - start
print(string.format("执行时间: %.6f秒", elapsed))
return table.unpack(result)
end
-- 使用
profile(function()
local sum = 0
for i = 1, 1000000 do
sum = sum + i
end
return sum
end)