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 = 10local b = 20print(a + b)
endtest()
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
endlocal 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 = 10local b = 20local name, value = debug.getlocal(1, 1)  -- 获取第一个局部变量print("Variable name value:", name, value)
endtest()

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

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

注意事项

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

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

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

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

5. debug.getupvalue(func, upvalue_index)

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

local function outer()local x = 10local y = 11local function inner()return x, yendreturn inner
endlocal 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 = 10local function inner()return xendreturn inner
endlocal inner = outer()
debug.setupvalue(inner, 1, 20)  -- 修改上值
print(inner())  -- 输出 20

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

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

local function causeError()error("An error occurred!")
endlocal function errorHandler()local message = debug.traceback("", 2)print("Error stack trace:\n" .. message)
endxpcall(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!")
enddebug.sethook(hook, "l")  -- 每次执行一行代码时调用 hooklocal function sampleFunction()print("Inside sample function.")
endsampleFunction()
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 = 10local function inner()return xendreturn inner
endlocal 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 = 10return function() return x end
endlocal function closure2()local y = 20return 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.mzph.cn/web/64150.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【再谈设计模式】享元模式~对象共享的优化妙手

一、引言 在软件开发过程中,我们常常面临着创建大量细粒度对象的情况,这可能会导致内存占用过高、性能下降等问题。享元模式(Flyweight Pattern)就像是一位空间管理大师,它能够在不影响功能的前提下,有效地…

Milvus×EasyAi:如何用java从零搭建人脸识别应用

如何从零搭建一个人脸识别应用?不妨试试原生Java人工智能算法:EasyAi Milvus 的组合拳。 本文将使用到的软件和工具包括: EasyAi:人脸特征向量提取Milvus:向量数据库用于高效存储和检索数据。 01. EasyAi:…

NS3学习——tcpVegas算法代码详解(2)

NS3学习——tcpVegas算法代码详解(1)-CSDN博客 目录 4.TcpVegas类中成员函数 (5) CongestionStateSet函数 (6) IncreaseWindow函数 1.检查是否启用 Vgas 2.判断是否完成了一个“Vegas 周期” 2.1--if:判断RTT样本数量是否足够 2.2--e…

GitLab 将停止为中国区用户提供服务,60天迁移期如何应对? | LeetTalk Daily

“LeetTalk Daily”,每日科技前沿,由LeetTools AI精心筛选,为您带来最新鲜、最具洞察力的科技新闻。 GitLab作为一个广受欢迎的开源代码托管平台,近期宣布将停止服务中国大陆、澳门和香港地区的用户提供服务。根据官方通知&#x…

华为实训课笔记 2024 1223-1224

华为实训 12/2312/24 12/23 [Huawei]stp enable --开启STP display stp brief --查询STP MSTID Port Role STP State Protection 实例ID 端口 端口角色 端口状态 是否开启保护[Huawei]display stp vlan xxxx --查询制定vlan的生成树计算结…

《Java源力物语》-3.空值猎手

~犬📰余~ “我欲贱而贵,愚而智,贫而富,可乎? 曰:其唯学乎” \quad 夜色渐深,在一处偏僻小径上,月光透过浓密的源力云层,在地面上投下斑驳的光影。String正独自练习着刚从…

科技云报到:人工智能时代“三大件”:生成式AI、数据、云服务

科技云报到原创。 就像自行车、手表和缝纫机是工业时代的“三大件”。生成式AI、数据、云服务正在成为智能时代的“新三大件”。加之全球人工智能新基建加速建设,成为了人类社会数字化迁徙的助推剂,让新三大件之间的耦合越来越紧密。从物理世界到数字世…

hiprint结合vue2项目实现静默打印详细使用步骤

代码地址是:vue-plugin-hiprint: hiprint for Vue2/Vue3 ⚡打印、打印设计、可视化设计器、报表设计、元素编辑、可视化打印编辑 本地安装包地址:electron-hiprint 发行版 - Gitee.com 1、先安装hipint安装包在本地 2、项目运行npm(socket.…

CUDA各种内存和使用方法

文章目录 1、全局内存2、局部内存3、共享内存3.1 静态共享内存3.2 动态共享内存 4、纹理内存5、常量内存6、寄存器内存7、用CUDA运行时API函数查询设备CUDA 错误检测 1、全局内存 特点:容量最大,访问延时最大,所有线程都可以访问。 线性内存…

Chapter 03 复合数据类型-1

1.列表 Python内置的一种有序、可变的序列数据类型; 列表的定义: [ ]括起来的逗号分隔的多个元素组成的序列 列表对象的创建: (1)直接赋值 >>> list1 []#创建一个空列表赋值给list1 >>> list…

【后端】LNMP环境搭建

长期更新各种好文,建议关注收藏! 本文近期更新完毕。 LNMPlinuxnginxmysqlphp 需要的资源 linux服务器 web服务软件nginx 对应的语言编译器代码文件 数据库mysql安装 tar.gz包或者命令行安装 进入root: sodu 或su mkdir path/{server,soft}…

基于PyQt5的UI界面开发——多界面切换

介绍 最初,因为课设的缘故,我只是想做一个通过按键进行切面切换而已,但是我看网上资料里面仅是语焉不详,让我困惑的很,但后面我通过摸索才发现这件事实在是太简单了,因此我想要记录下来。 本博客将介绍如…

操作002:HelloWorld

文章目录 操作002:HelloWorld一、目标二、具体操作1、创建Java工程①消息发送端(生产者)②消息接收端(消费者)③添加依赖 2、发送消息①Java代码②查看效果 3、接收消息①Java代码②控制台打印③查看后台管理界面 操作…

机器视觉检测相机基础知识 | 颜色 | 光源 | 镜头 | 分辨率 / 精度 / 公差

注:本文为 “keyence 视觉沙龙中机器视觉检测基础知识” 文章合辑。 机器视觉检测基础知识(一)颜色篇 视觉检测硬件构成的基本部分包括:处理器、相机、镜头、光源。 其中,和光源相关的最重要的两个参数就是光源颜色和…

【体验官招募】SoFlu - JavaAI 开发助手:开启智能开发新时代

你是否有过这样的经历?在深夜的办公室里,面对紧急的 Java 项目,看着厚厚的需求文档,你是否感到无从下手? 当你尝试理解客户那些复杂又模糊的需求时,是否会因为要和产品经理反复沟通确认每一个细节而感到厌…

自学记录HarmonyOS Next DRM API 13:构建安全的数字内容保护系统

在完成了HarmonyOS Camera API的开发之后,我开始关注更复杂的系统级功能。在浏览HarmonyOS Next文档时,我发现了一个非常有趣的领域:数字版权管理(DRM)。最新的DRM API 13提供了强大的工具,用于保护数字内容…

【HENU】河南大学计院2024 操作系统 简答题复习

和光同尘_我的个人主页 一直游到海水变蓝。 单项选择 15x2 30 判断 10x1 10 简答 3x10 30 综合 3x10 30 简答题 简述操作系统的四个基本特征。 并发性 共享性 虚拟性 异步性 并发性是最重要特性,其它三种特性以此为前提。 并发 并发(Concurrence)&#…

GEE错误——PCA系数变换的时候出现的错误

目录 错误提示1 错误提示2 原始的教程链接: 错误代码 修正后的代码 结果 错误提示1 这个是因为原始GEE教程中给的让我们填入需要进行计算的波段名称,而且是以list的形式传入。 错误提示2 这里我们虽然传入了正确的波段名称,但是发现要…

C#代码实现把中文录音文件(.mp3 .wav)转为文本文字内容

我们有一个中文录音文件.mp3格式或者是.wav格式,如果我们想要提取录音文件中的文字内容,我们可以采用以下方法,不需要使用Azure Speech API 密钥注册通过离线的方式实现。 1.首先我们先在NuGet中下载两个包 NAudio 2.2.1、Whisper.net 1.7.3…

计算机操作系统与安全复习笔记

1 绪论 操作系统目标: 方便性; 有效性; 可扩充性; 开放性. 作用: 用户与计算机硬件系统之间的接口; 计算机资源的管理者; 实现了对计算机资源的抽象; 计算机工作流程的组织者. 多道程序设计: 内存中同时存放若干个作业, 使其共享系统资源且同时运行; 单处理机环境下宏观上并行…