当前位置: 首页 > article >正文

lua debug相关方法详解

lua debug相关方法详解

  • 1. debug.debug()
  • 2. debug.getinfo(func | level [, what])
  • 3. debug.getlocal(func-or-level, localindex)
  • 4. debug.setlocal(level, local_number, value)
  • 5. debug.getupvalue(func, upvalue_index)
  • 6. debug.setupvalue(func, upvalue_index, value)
  • 7. debug.traceback([thread,] [message [, level]])
  • 8. debug.sethook(func, mask [, count])
  • 9. debug.getregistry()
  • 10. debug.getmetatable(object)
  • 11. debug.setmetatable(object, metatable)
  • 12. debug.upvalueid(f, n)
  • 13. debug.upvaluejoin(f1, n1, f2, n2)

在 Lua 中,debug 库提供了一组强大的函数,用于调试和跟踪代码的执行,这些函数可用于查看堆栈信息、检查运行时状态、设置钩子等

1. debug.debug()

该函数在交互模式下进入调试器,允许用户逐步执行代码

local function test()
    local a = 10
    local b = 20
    print(a + b)
end

test()
debug.debug()  -- 触发调试器

执行 debug.debug() 将转到调试模式

2. debug.getinfo(func | level [, what])

此函数返回指定函数或调用的当前状态信息,level 是调用堆栈的深度,what 用于指定返回的信息类型(默认值为"flnSu"),第一个参数可以是一个函数或一个整数,如果是函数,debug.getinfo返回关于该函数的信息,如果是整数,表示调用栈的层级

what 参数可以是:

  • f:返回函数对象
  • n:返回函数的名称
  • l:返回当前执行的行号
  • S:返回源代码文件名和行号
  • L:返回当前函数的所有行号范围
  • u:返回函数的未使用参数的数量
  • t:返回函数类型(C 函数或 Lua 函数)
  • g:返回生成器的上下文

debug.getinfo 返回一个包含调试信息的表,表中可能包含以下字段:

  • name:函数的名称
  • namewhat:函数名称的类型,可以是 “global”, “local”, “field”, “method” 或 “”
  • func:函数对象
  • source:源代码文件名(以 @ 开头表示文件,以 = 开头表示匿名函数)
  • short_src:源代码文件的简短名称
  • linedefined:函数定义的起始行号
  • lastlinedefined:函数定义的结束行号
  • currentline:当前执行的行号
  • nups:函数的上值数量
  • nparams:函数的参数数量
  • isvararg:函数是否是可变参数函数
  • istailcall:当前是否是尾调用
  • isC:函数是否是 C 函数
  • isyieldable:函数是否可以挂起
local function sample()
    return 42
end

local info = debug.getinfo(sample)
print(info.source)  -- 打印函数的源代码路径
print(info.linedefined)  -- 打印函数开始的行号

3. debug.getlocal(func-or-level, localindex)

返回指定级别的本地变量的值

  • func-or-level:
    • 可以是一个函数,表示要获取局部变量的函数
    • 也可以是一个整数,表示调用栈的层级,1 表示当前函数,2 表示调用当前函数的函数,依此类推
  • localindex:
    • 局部变量的索引,从 1 开始,可以使用负数来表示从最后一个局部变量开始计数
  • 返回值:
    • 局部变量的值
    • 如果变量不存在,返回 nil

获取当前函数的局部变量:

function test()
  local a = 10
  local b = 20
  local name, value = debug.getlocal(1, 1)  -- 获取第一个局部变量
  print("Variable name value:", name, value)
end

test()

获取调用栈中上一层函数的局部变量:

function outer()
  local x = 100
  inner()
end

function inner()
  local name, value = debug.getlocal(2, 1)  -- 获取外层函数的第一个局部变量
  print("Outer variable name value:", name, value)
end

outer()

注意事项

  • debug.getlocal 返回的表包含变量的名称和值
  • 使用负数索引时,-1 表示最后一个局部变量,-2 表示倒数第二个,依此类推
  • 如果函数没有局部变量,或者指定的索引超出范围,返回 nil

4. debug.setlocal(level, local_number, value)

设置指定级别的本地变量的值

local function bar()
    local x = 10
    local y = 20
    debug.setlocal(1, 1, 30)  -- 将第一个本地变量的值设置为 30
    print(x)  -- 输出 30
end

bar()

5. debug.getupvalue(func, upvalue_index)

该函数用于获取函数的上值(upvalue)信息,上值是 Lua 中函数闭包的概念,允许函数访问其定义环境中的局部变量,通过debug.getupvalue可查看函数的上值名称和对应的值

local function outer()
    local x = 10
    local y = 11
    local function inner()
        return x, y
    end
    return inner
end

local inner = outer()
local name1, value1 = debug.getupvalue(inner, 1)  -- 获取上值的值
local name2, value2 = debug.getupvalue(inner, 1)  -- 获取上值的值
print(name1, value1, name2, value2)  -- 输出 x 10 y 11

6. debug.setupvalue(func, upvalue_index, value)

设置指定函数的上值

local function outer()
    local x = 10
    local function inner()
        return x
    end
    return inner
end

local inner = outer()
debug.setupvalue(inner, 1, 20)  -- 修改上值
print(inner())  -- 输出 20

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

返回当前堆栈的完整调用回溯,通常用于错误处理

local function causeError()
    error("An error occurred!")
end

local function errorHandler()
    local message = debug.traceback("", 2)
    print("Error stack trace:\n" .. message)
end

xpcall(causeError, errorHandler)

8. debug.sethook(func, mask [, count])

设置一个钩子函数,可使程序在每次调用或返回时执行指定的函数

hook, mask, count = debug.sethook([function [, mask [, count]]])
  • function:
    • 钩子函数,当满足特定条件时会被调用
    • 如果设置为 nil,则取消当前的调试钩子
  • mask: 控制钩子的触发条件,可以是以下值的任意组合:
    • ‘c’: 每次调用
    • ‘r’: 每次返回
    • ‘l’: 每行代码执行时
    • “count”:每隔 count 次执行调用钩子函数
  • count(可选):
    • 仅当 mask 包含"count" 时有效,指定每隔多少次执行调用钩子函数
local function hook()
    print("A line was executed!")
end

debug.sethook(hook, "l")  -- 每次执行一行代码时调用 hook

local function sampleFunction()
    print("Inside sample function.")
end

sampleFunction()
debug.sethook()  -- 取消钩子

9. debug.getregistry()

返回注册表(registry)表,Lua 使用这个表来存储全局数据

local registry = debug.getregistry()
print(registry)  -- 输出注册表的内容

10. debug.getmetatable(object)

获取指定对象的元表(metatable)

local t = {}
local mt = { __index = function(t, k) return k end }
setmetatable(t, mt)

local meta = debug.getmetatable(t)
print(meta)  -- 输出元表

与getmetatable主要区别

  1. 权限检查:
  • getmetatable 会尊重 __metatable 字段的设置,如果 __metatable 为 nil,则返回 nil;如果 __metatable 为其他值,则返回该值
  • debug.getmetatable 忽略 __metatable 字段的设置,总是返回对象的实际元表
  1. 使用场景:
  • 标准用途:如果只是想获取对象的元表,并且尊重 __metatable 字段的保护机制,使用 getmetatable
  • 调试用途:如果需要绕过 __metatable 的保护机制,获取对象的实际元表,使用 debug.getmetatable
  1. 安全性:
  • getmetatable 更安全,因为它尊重 __metatable 字段的设置,可以防止未经授权的访问和修改
  • debug.getmetatable 由于可以绕过保护机制,使用时需要特别小心,以免破坏程序的正常运行

11. debug.setmetatable(object, metatable)

设置指定对象的元表

local t = {}
local mt = { __index = function(t, k) return k end }
debug.setmetatable(t, mt)

print(getmetatable(t))  -- 输出新的元表

与setmetatable主要区别

  1. 权限检查:
  • setmetatable 会尊重 __metatable 字段的保护机制,如果元表被保护,则无法修改,会抛出错误
  • debug.setmetatable 无视 __metatable 字段的保护机制,可以强制修改元表
  1. 使用场景:
  • 标准用途:如果只是想设置或修改对象的元表,并且尊重 __metatable 字段的保护机制,使用 setmetatable
  • 调试用途:如果需要绕过 __metatable 的保护机制,强制修改对象的元表,使用 debug.setmetatable
  1. 安全性:
  • setmetatable 更安全,因为它尊重 __metatable 字段的保护机制,可以防止未经授权的修改
  • debug.setmetatable 由于可以绕过保护机制,使用时需要特别小心,以免破坏程序的正常运行
  1. 返回值:
  • setmetatable 返回设置元表后的对象,可以用于链式操作
  • debug.setmetatable 没有返回值

12. debug.upvalueid(f, n)

返回指定函数第 n 个上值的唯一标识符, 可以用来判断两个函数引用的 upvalue 是否是同一个值

local function outer()
    local x = 10
    local function inner()
        return x
    end
    return inner
end

local inner = outer()
local upvalueId = debug.upvalueid(inner, 1)
print(upvalueId)  -- 输出上值的唯一标识符

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

将两个函数的第 n1 和 n2 个上值关联起来,可将一个闭包的上值连接到另一个闭包的上值,以实现上值的共享

使用场景

  1. 共享状态:当需要多个闭包共享同一个变量时,可以通过 debug.upvaluejoin 来实现
  2. 调试和测试:在调试过程中,可能需要修改闭包的上值,以观察不同的行为
  3. 高级编程技巧:在某些高级编程技巧中,可能需要手动管理闭包的上值
-- 定义两个闭包,每个闭包有一个上值
local function closure1()
    local x = 10
    return function() return x end
end

local function closure2()
    local y = 20
    return function() return y end
end

-- 创建两个闭包实例
local func1 = closure1()
local func2 = closure2()

-- 获取上值的索引
local up1_name, up1_value = debug.getupvalue(func1, 1)
local up2_name, up2_value = debug.getupvalue(func2, 1)

-- 连接上值
debug.upvaluejoin(func1, 1, func2, 1)

print(func1())  --> 输出20 是closure2的上值,触发了共享值

注意事项

  1. 风险:不正确的使用 debug.upvaluejoin 可能会导致程序行为不可预测,因此在使用时需要非常小心
  2. 性能:频繁地操作上值可能会影响性能,应尽量避免在性能敏感的代码中使用
  3. 可维护性:过度使用调试函数可能降低代码的可读性和可维护性,应尽量在必要时使用

http://www.kler.cn/a/454887.html

相关文章:

  • UE(虚幻)学习(三) UnrealSharp插件中调用非托管DLL
  • Nginx的性能分析与调优简介
  • C++ 泛编程 —— 嵌套使用模板类
  • KNN分类算法 HNUST【数据分析技术】(2025)
  • K8s 常用资源介绍
  • 【自留】Unity VR入门
  • leetcode82:删除链表中的重复元素II
  • 【蓝桥杯】走迷宫
  • 题海拾贝:蓝桥杯 2020 省AB 乘法表
  • 免费资源网站
  • ANSYS EMC Plus:谐振腔中的天线
  • Markdown语法字体字号讲解
  • git revert
  • 【C#】WPF设置Separator为垂直方向
  • (icml2024)SLAattention,基于原文时序模型进行改进
  • 【AIGC篇】AIGC 引擎:点燃创作自动化的未来之火
  • 项目报 OutOfMemoryError 、GC overhead limit exceeded 问题排查以及解决思路实战
  • LeetCode 热题 100_二叉树的中序遍历(36_94_简单_C++)(二叉树;递归(中序遍历);迭代)
  • 如何在 Ubuntu 22.04 上安装 Ansible 教程
  • OpenStack系列第三篇:CentOS7 上部署 OpenStack(Train版)集群教程 Ⅲ Nova Neutron 服务部署
  • Go语言反射从入门到进阶
  • js 生成二维码(qrcodejs2-fix)
  • Intel AMD Hygon CPU缓存
  • 分阶段总结:建材制造业“数字化转型”总体架构与实现路径
  • 06 - Django 视图view
  • 拉链表,流⽔表以及快照表的含义和特点