lua debug相关方法详解

lua debug相关方法详解

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

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

1. debug.debug()

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

lua 复制代码
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:函数是否可以挂起
lua 复制代码
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

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

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

test()

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

lua 复制代码
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)

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

lua 复制代码
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可查看函数的上值名称和对应的值

lua 复制代码
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)

设置指定函数的上值

lua 复制代码
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]])

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

lua 复制代码
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])

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

lua 复制代码
hook, mask, count = debug.sethook([function [, mask [, count]]])
  • function:
    • 钩子函数,当满足特定条件时会被调用
    • 如果设置为 nil,则取消当前的调试钩子
  • mask: 控制钩子的触发条件,可以是以下值的任意组合:
    • 'c': 每次调用
    • 'r': 每次返回
    • 'l': 每行代码执行时
    • "count":每隔 count 次执行调用钩子函数
  • count(可选):
    • 仅当 mask 包含"count" 时有效,指定每隔多少次执行调用钩子函数
lua 复制代码
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 使用这个表来存储全局数据

lua 复制代码
local registry = debug.getregistry()
print(registry)  -- 输出注册表的内容

10. debug.getmetatable(object)

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

lua 复制代码
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)

设置指定对象的元表

lua 复制代码
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 是否是同一个值

lua 复制代码
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. 高级编程技巧:在某些高级编程技巧中,可能需要手动管理闭包的上值
lua 复制代码
-- 定义两个闭包,每个闭包有一个上值
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. 可维护性:过度使用调试函数可能降低代码的可读性和可维护性,应尽量在必要时使用
相关推荐
Godlovesea几秒前
ubuntu控制器多网口配置
开发语言·php
A懿轩A10 分钟前
C/C++ 数据结构与算法【哈夫曼树】 哈夫曼树详细解析【日常学习,考研必备】带图+详细代码
c语言·c++·学习·算法·哈夫曼树·王卓
新中地GIS开发老师12 分钟前
25考研希望渺茫,工作 VS 二战,怎么选?
javascript·学习·考研·arcgis·地理信息科学·地信
sensen_kiss17 分钟前
CAN201 Introduction to Networking(计算机网络)Pt.3 网络层
网络·学习·计算机网络·智能路由器
web1368856587122 分钟前
rust教程 第一章 —— 初识rust
开发语言·后端·rust
songroom24 分钟前
Rust : tokio中select!
开发语言·后端·rust
dubochao_xinxi25 分钟前
QT5 在某些系统出现qt.qpa.xcb: could not connect
开发语言·qt
blueman888827 分钟前
QWidget应用封装为qt插件,供其他qt应用调用
开发语言·qt
qincjun29 分钟前
Qt仿音乐播放器:设置窗口、部件属性
开发语言·qt
编码小哥38 分钟前
C++线程同步和互斥
开发语言·c++