Lua Carp |
|
level
参数,该参数指示在生成错误消息时,调用堆栈中哪个级别应该被指责。现在,这并不总是可扩展的,因为跟踪级别可能会容易出错(尤其是在重构之后),并且使用 error
的函数可能会在多个不同的级别被调用。
下面的解决方案基于 [Perl 的 Carp] 模块,但已适应 Lua。这提供了一个 croak
函数来替换 error
。croak
调用 error
,但在这样做之前,它会通过查找调用堆栈来确定要使用的级别,直到当前环境发生变化。
首先,这是主模块
-- Carp.lua -- This package is based on Perl Carp -- (http://search.cpan.org/~nwclark/perl-5.8.8/lib/Carp.pm) -- David Manura, 2006-09, 2007-07 local M = {} function M.croak(message) local current_env = getfenv(2) local level = 2 while true do local is_success, result = pcall(function() return getfenv(level + 2) end) if is_success then local env = result --print("DEBUG:level", level, env._NAME) if env ~= current_env then --print("DEBUG:found", level, env._NAME) error(message, level) end elseif string.find(result, "(invalid level)") then break end level = level + 1 end end return M
现在假设你编写了一个模块
-- Calculator.lua -- Create environment for module (needed for Carp) local env = setmetatable({}, {__index = _G}) setfenv(1, env) local M = {} local Carp = require "Carp" function M.calculate3() Carp.croak("calculation failed") return 1 end function M.calculate2() local result = M.calculate3() return result + 1 end function M.calculate() return M.calculate2() end return M
你编写了一个使用该模块的程序
-- example.lua -- This uses the calculator module. local Calc = require "Calculator" local function main() local result = Calc.calculate() print(result) end main()
这是输出
lua: example.lua:7: calculation failed stack traceback: [C]: in function 'error' ./Carp.lua:20: in function 'croak' ./Calculator.lua:10: in function 'calculate3' ./Calculator.lua:15: in function <./Calculator.lua:14> (tail call): ? example.lua:7: in function 'main' example.lua:11: in main chunk [C]: ?
注意:这可能不适用于尾调用。尾调用将被跳过,因为 Lua 不会为它们报告环境。
RiciLake 提出的第二种替代方法是编写一个自定义的回溯函数,其思想是回溯函数检查每个级别的 env 表,并且只有在 env 表与当前 env 表不同时才开始生成回溯。
RiciLake 提出的第三种方法是简单地检查每个帧中堆栈索引 1 处的对象,其思想是,如果你嵌套了方法调用,你将始终具有相同的 self,但有时会超出范围。人们希望以某种方式标记堆栈,但如何做到这一点并不明显。
TODO--关于这些方法优缺点的评论,有人吗?
注意:代码与 Lua 5.1(而不是 5.0)兼容。