国际访客建议访问 Primers 编程伙伴 国际版站点 > Lua 教程 > debug-module 以获得更好的体验。

# Lua 的 Debug 模块

请查看 Lua 标准库模块列表 了解更多相关 API。

Debug 模块为 Lua 程序提供了调试接口。使用此模块时应格外小心,其中的一些函数违反了 Lua 代码的基本假设(例如,函数内部的变量不能从外部访问;用户数据元表不能被 Lua 代码修改;Lua 程序不会崩溃),因此可能会危及原本安全的代码。并且某些函数可能运行缓慢。

函数 说明
debug.debug) 启动调试模式
debug.getinfo) 获取函数信息
debug.gethook) 获取调试钩子
debug.sethook) 设置调试钩子
debug.getlocal) 获取栈上局部变量
debug.setlocal) 设置栈上局部变量
debug.getmetatable) 获取元表
debug.setmetatable) 设置元表
debug.getregistry) 获取注册表
debug.getupvalue) 获取闭包上值表
debug.setupvalue) 设置闭包上值表
debug.upvalueid) 获取闭包上值 ID
debug.upvaluejoin) 使闭包引用另一个闭包的上值
debug.getuservalue) 获取用户值
debug.setuservalue) 设置用户值
debug.traceback) 获取栈的回溯信息

# debug.debug

debug.debug ()

!subtitle:说明

进入调试模式的交互式命令行,将用户输入的字符串作为 Lua 代码运行,输入 cont 即可退出调试模式继续运行程序。

!subtitle:参数

!subtitle:返回值

!subtitle:示例

运行示例

local n = 10                    -- 不能访问局部变量
text = "https://xplanc.org/"    -- 可以访问全局变量
debug.debug ()

# debug.gethook

debug.gethook ([thread])

!subtitle:说明

获取线程 thread 的调试钩子函数。

!subtitle:参数

  • thread - 线程;默认为当前线程

!subtitle:返回值

  • 返回调试钩子函数

# debug.getinfo

debug.getinfo ([thread,] f [, what])

!subtitle:说明

获取函数信息的表。

!subtitle:参数

  • thread - 线程;默认为当前线程

  • f - 函数或函数在栈上的层级

  • what - 指定想要的信息;默认为 "nSluf"

what 接受的值 含义
n 函数名及调用方式(name, namewhat
S 源代码信息(short_src, linedefined, lastlinedefined, what, source
l 当前行号(currentline
u 函数的上值与参数信息(nups, nparams, isvararg
f 返回实际的函数本身(func
L 包含该函数中哪些行有可执行代码(activelines 表)

!subtitle:返回值

  • 返回函数信息表

!subtitle:示例

运行示例

function level1()
    print(debug.getinfo(0)['name'])     -- 按栈上位置获取信息
    print(debug.getinfo(1)['name'])
    print(debug.getinfo(2)['name'])
    print(debug.getinfo(3)['name'])
end

function level2()
    level1()
end

function level3()
    level2()
end

function main()
    level3()
end

main()

local info = debug.getinfo(main, 'nl')  -- 获取指定函数信息
for k,v in pairs(info) do
    print(k, v)
end

# debug.getlocal

debug.getlocal ([thread,] f, local)

!subtitle:说明

获取栈上 f 层级中第 local 个局部变量。

!subtitle:参数

  • thread - 线程;默认为当前线程

  • f - 栈上层级

  • local - 局部变量的序号

!subtitle:返回值

  • 成功时返回局部变量的名称和值

  • 失败时返回 nil

!subtitle:示例

运行示例

function demo()
    local x = 10
    local y = 20
    local z = 30

    print(debug.getlocal(1, 1))
    print(debug.getlocal(1, 2))
    print(debug.getlocal(1, 3))
end

demo()

# debug.getmetatable

debug.getmetatable (value)

!subtitle:说明

获取 value 的元表。

!subtitle:参数

  • value - 要获取元表的对象

!subtitle:返回值

  • 返回对象的元表

!subtitle:示例

运行示例

local metatable = debug.getmetatable("") -- 获取字符串的元表
for k,v in pairs(metatable) do
    print(k, v)
end

# debug.getregistry

debug.getregistry ()

!subtitle:说明

获取注册表。

Lua 的注册表是一个由 C API 维护的全局表,用于在 C 和 Lua 之间安全地交换和保存数据,始终可以通过伪索引 LUA_REGISTRYINDEX 进行访问。

!subtitle:参数

!subtitle:返回值

  • 返回 Lua 的注册表

!subtitle:示例

运行示例

for k,v in pairs(debug.getregistry()) do
    print(k, v)
end

# debug.getupvalue

debug.getupvalue (f, up)

!subtitle:说明

获取闭包 f 的第 up 个上值。

!subtitle:参数

  • f - 闭包

  • up - 上值的序号

!subtitle:返回值

  • 成功时返回上值的的名称和值

  • 失败时返回 nil

!subtitle:示例

运行示例

function demo()
    local x = 10    -- 外层局部变量,即上值
    local y = 20
    local z = 30

    -- 返回闭包
    return function()
        print(x, z) -- 只有被引用的外层变量才会被捕获为上值
    end
end

-- 创建闭包
local closure = demo()

print(debug.getupvalue(closure, 1)) -- _ENV,调用函数时会创建这个局部变量
print(debug.getupvalue(closure, 2)) -- x
print(debug.getupvalue(closure, 3)) -- z

# debug.getuservalue

debug.getuservalue (u, n)

!subtitle:说明

获取与用户数据 u 关联的第 n 个用户值。

!subtitle:参数

  • u - 用户数据

  • n - 用户值的序号

!subtitle:返回值

  • 成功时返回用户的的名称和值

  • 失败时返回 nil

# debug.sethook

debug.sethook ([thread,] hook, mask [, count])

!subtitle:说明

设置调试钩子函数,钩子函数在特定事件发生时被调用。

只有最后一个钩子是有效的,无法为不同的事件同时设置钩子。

!subtitle:参数

  • thread - 线程;默认为当前线程

  • hook - 钩子函数

  • mask - 事件掩码组合字符串

    • 'c' - 每次 Lua 调用函数时都会调用该钩子函数,参数为事件

    • 'r' - 每次 Lua 从函数返回时都会调用该钩子函数,参数为事件

    • 'l' - 每次 Lua 进入新行时该钩子函数,参数为事件和行号

  • count - 除事件外,每执行 count 条指令触发一次钩子函数;默认为 0 不触发

!subtitle:返回值

!subtitle:示例

运行示例

local function hook(event, line)
    print(event, line)
end

debug.sethook(hook, "l")    -- 每行触发

-- 空行不会触发钩子

print("NOP")
print("NOP")
print("NOP")

# debug.setlocal

debug.setlocal ([thread,] level, local, value)

!subtitle:说明

将栈上 level 层级处的第 local 个局部变量的值设为 value

!subtitle:参数

  • thread - 线程;默认为当前线程

  • f - 栈上层级

  • local - 局部变量的序号

  • value - 要设为的值

!subtitle:返回值

  • 成功时返回被修改的变量名

  • 失败时返回 nil

!subtitle:示例

运行示例

function inner()
    debug.setlocal(2, 1, "Hello")
    debug.setlocal(2, 2, "Primers")
    debug.setlocal(2, 3, "编程伙伴")
end

function outer()
    local x = 10
    local y = 20
    local z = 30

    inner()

    print(x, y, z)
end

outer()

# debug.setmetatable

debug.setmetatable (value, table)

!subtitle:说明

将对象 value 的元表设为 metatable;如果 value 已有的元表包含 __metatable 字段则会引发错误。

!subtitle:参数

  • value - 要设置元表的对象,可以时表或用户数据

  • metatable - 要设置的元表,如果是 nil 则移除对象的元表

!subtitle:返回值

  • 返回 value

!subtitle:示例

运行示例

local t1 = {value = 10}
local t2 = {value = 20}

-- 元表,重载运算符
local metatable = {
    __add = function(x, y) return {value = x.value + y.value} end,
    __sub = function(x, y) return {value = x.value - y.value} end,
    __mul = function(x, y) return {value = x.value * y.value} end,
    __div = function(x, y) return {value = x.value / y.value} end,
}

-- 设置元表
debug.setmetatable(t1, metatable)
debug.setmetatable(t2, metatable)

-- 使用
print((t1 + t2).value)
print((t1 - t2).value)
print((t1 * t2).value)
print((t1 / t2).value)

# debug.setupvalue

debug.setupvalue (f, up, value)

!subtitle:说明

将闭包 f 的第 up 个上值设为 value

!subtitle:参数

  • f - 闭包

  • up - 上值的序号

  • value - 要设为的值

!subtitle:返回值

  • 被修改的上值变量名

!subtitle:示例

运行示例

-- 外层局部变量,即上值
local x = 10
local y = 20
local z = 30

-- 创建闭包
local closure = function()
    print(x, y, z) -- 只有被引用的外层变量才会被捕获为上值
end

-- 修改上值
debug.setupvalue(closure, 2, 'Hello')
debug.setupvalue(closure, 3, 'Primers')
debug.setupvalue(closure, 4, '编程伙伴')

-- 调用闭包
closure()

-- 外层变量也被改变
print(x, y, z)

# debug.setuservalue

debug.setuservalue (u, value, n)

!subtitle:说明

将与用户数据 u 关联的第 n 个用户值设置 value

!subtitle:参数

  • u - 用户数据

  • value - 要设为的值

  • n - 用户数据的序号

!subtitle:返回值

  • 返回 u

# debug.traceback

debug.traceback ([thread,] [message [, level]])

!subtitle:说明

生成调用栈回溯信息。

!subtitle:参数

  • thread - 线程;默认为当前线程

  • message - 附加信息;如果这个参数不是字符串或 nil 则直接返回这个参数

  • level - 从调用栈的第几层开始记录

!subtitle:返回值

  • 返回生成的信息

!subtitle:示例

运行示例

function level1()
    print(debug.traceback("附加信息 https://xplanc.org/"))
end

function level2()
    level1()
end

function level3()
    level2()
end

function main()
    level3()
end

main()

# debug.upvalueid

debug.upvalueid (f, n)

!subtitle:说明

获取闭包 f 的第 up 个上值的唯一 ID(类型为轻量用户数据)。

通过返回的 ID 可以检测不同的闭包是否引用同一个上值。

!subtitle:参数

  • f - 闭包

  • up - 上值的序号

!subtitle:返回值

  • 返回上值的唯一 ID(轻量用户数据)

!subtitle:示例

运行示例

local function outer()
    local a = 10
    local b = 20

    local function f1() return a end
    local function f2() return a end
    local function f3() return b end

    return f1, f2, f3
end

local f1, f2, f3 = outer()

local id1 = debug.upvalueid(f1, 1)
local id2 = debug.upvalueid(f2, 1)
local id3 = debug.upvalueid(f3, 1)

print(id1 == id2)  --> true   (f1 和 f2 的上值 a 是同一个)
print(id1 == id3)  --> false  (f1 的 a 和 f3 的 b 不同)

# debug.upvaluejoin

debug.upvaluejoin (f1, n1, f2, n2)

!subtitle:说明

让闭包 f1 的第 n1 个上值引用闭包 f2 的第 n2 个上值。

!subtitle:参数

  • f1 - 目标闭包

  • n1 - 目标上值序号

  • f2 - 源闭包

  • n2 - 源上值序号

!subtitle:返回值

!subtitle:示例

运行示例

local function outer()
    local a = 10
    local b = 20

    local function f1() return a end -- 引用 a
    local function f2() return b end -- 引用 b

    return f1, f2
end

local f1, f2 = outer()

-- 打印原始值
print(f1(), f2())  --> 10 20

-- 让 f2 的上值指向 f1 的上值
debug.upvaluejoin(f2, 1, f1, 1)

print(f1(), f2())  --> 10 10

# 推荐阅读

The Debug Library - Lua 5.4 Reference Manual

本文 更新于: 2025-11-27 09:38:13 创建于: 2025-11-27 09:38:13