一、调试库作用
使用调试库可以获取 Lua 环境运行过程中的变量和跟踪代码执行。
调试库主要分为两类函数:自省函数和钩子函数
- 自省函数:允许检查一个正在运行中的程序,例如活动函数的栈、当前正在执行的代码行、局部变量的名称和值。
- 钩子函数:允许跟踪一个程序的执行。
值得注意:
调试库的某些功能性能不高,而且会打破语言的一些固有规则。
二、自省函数
1、debug.getinfo(thread, f, what)
该函数会返回包含函数信息的表。
参数:
- thread: 表示在 thread 中获取相应的信息
- f: 可以给两种模式,函数或数值。第一种则是给函数,获取给定函数的信息表。第二种则是给一个数字作为
f
的值,表示栈层级:当为 0 时表示当前函数( 即getinfo
本身), 1 表示调用getinfo
的函数(尾调用除外,它们不计入堆栈),以此类推。如果f
是一个大于活跃栈层级的数字,则getinfo
返回 nil。 - what: 可选项,表示要获取哪些指定的信息。因为 getinfo 的效率不高,所以为了效率好些,可以只选择需要的内容,如果需要多个值时,可以将多个拼凑,例如
nfS
。
what 取值 | 获取的值 |
---|---|
n | 选择 name 和 namewhat |
f | 选择 func |
S | 选择 source、short_src、what、linedefined 和 lastlinedefined |
l | 选择 currentline |
L | 选择 activelines |
u | 选择 nup、nparams 和 isvararg |
这些字段的含义如下:
字段 | 描述 |
---|---|
name | 该字段是该函数的一个适当的名称,例如保存该函数的全局变量的名称。(可能没有值,也可能有多个名称)(只有当 f 为数值时才有该值) |
namewhat | 该字段用于说明 name 字段的含义,可能是 “global”、“local”、“method”、“field” 或 “”(空字符串)。空字符串表示 Lua 语言找不到该函数的名称。 |
func | 该字段是该函数本身 |
source | 该字段用于说明函数定义的位置。如果函数定义在一个字符串中(通过调用 load),那么 source 就是这个字符串;如果函数定义在一个文件中,那么 source 就是使用 @ 作为前缀的文件名 |
short_src | 该字段是 source 的精简版本(最多 60 个字符),对于错误信息十分有用。 |
what | 该字段用于说明函数的类型。 - 如果 foo 是一个普通的 Lua 函数,则为 “Lua” - 如果是一个 C 函数,则为 “C” - 如果是一个 Lua 语言代码段的主要部分,则为 “main” 。 |
linedefined | 该字段是该函数定义在源代码中第一行的行号 |
lastlinedefined | 该字段是该函数定义在源代码中最后一行的行号 |
currentline | 表示当前该函数正在执行的代码所在的行 (只有当 f 为数值时才有该值) |
istailcall | 返回一个布尔值,为真表示函数是被尾调用所调起(尾调用时,函数真正的调用者不在栈中)(只有 f 为数值时才有该值) |
activelines | 该字段是一个包含该函数所有活跃行的集合。活跃行是指除空行和只包含注释的行外的其它行(该字段的典型用法是用于设置断点。大多数调试器不允许在活跃行外设置断点,因为非活跃行是不可达的)。 |
nups | 该字段是该函数的上值的个数 |
nparams | 该字段是该函数的参数个数 |
isvararg | 该字段表明该函数是否为可变长函数 |
返回值:
如果传递的是一个函数或是一个合理的数值(小于等于栈层级),则会返回对应函数的信息表。如果超出的栈层级,则返回 nil
值得注意:
如果假设 foo 是一个 C 函数,Lua 语言没有多少关于该函数的信息。只有字段 what、name、namewhat、nups 和 func 是有意义的。
举两个例子:
输出一个函数的信息
function foo(a, b, ...)
print("江澎涌")
end
local info = debug.getinfo(foo)
for k, v in pairs(info) do
print(k, "---", v)
end
使用数值调用
foo1 = function(...)
local table = debug.getinfo(1)
for k, v in pairs(table) do
print(k, "---", v)
end
end
foo1()
上面例子中调用栈的层次如下:
2、traceback(thread, message, level)
返回调用栈信息
参数:
- thread: 表示在 thread 中获取相应的信息
- message:该参数没有限定为字符串,可以是任意的类型。如果为字符串或 nil ,则会返回调用栈的描述字符串,并且在最开始的地方拼接该 message (如果为 nil ,则不拼接)。如果为其他类型,则直接放回该值。
- level:调用层级,0 表示
traceback
函数,1 表示调用traceback
函数的函数,2 表示调用traceback
函数的函数的函数 …
返回值:
如果 message 为字符串或 nil ,则会返回调用栈的描述字符串,并且在最开始的地方拼接该 message (如果为 nil ,则不拼接)。如果为其他类型,则直接返回该值。
举个例子
print("没有参数")
local function foo1()
print(debug.traceback())
end
foo1()
--> 没有参数
--> stack traceback:
--> ...Lua/lua_study_2022/18 调试库/自省机制-getInfo.lua:58: in local 'foo1'
--> ...Lua/lua_study_2022/18 调试库/自省机制-getInfo.lua:60: in main chunk
--> [C]: in ?
print("携带 message(字符串)")
local function foo2()
print(debug.traceback("track back message."))
end
foo2()
--> 携带 message(字符串)
--> track back message.
--> stack traceback:
--> ...Lua/lua_study_2022/18 调试库/自省机制-getInfo.lua:64: in local 'foo2'
--> ...Lua/lua_study_2022/18 调试库/自省机制-getInfo.lua:66: in main chunk
--> [C]: in ?
print("携带 message(非字符串)")
local function foo3()
print(debug.traceback({