lua 热更新原理(二)

在讲lua热更新原理第二部分之前,先介绍一下lua调试相关的函数。

调试函数能够帮助我们在开发中获取函数堆栈相关上下文信息,甚至改变函数的变量。

getinfo ([thread,] f [, what]):

返回关于一个函数信息的表。 你可以直接提供该函数, 也可以用一个数字 f 表示该函数。 数字 f 表示运行在指定线程的调用栈对应层次上的函数: 0 层表示当前函数(getinfo 自身); 1 层表示调用 getinfo 的函数 (除非是尾调用,这种情况不计入栈);等等。 如果 f 是一个比活动函数数量还大的数字, getinfo 返回 nil。

例如代码是:

local function myfun()
    local a = 10
    local info = debug.getinfo(1)
    for k, v in pairs(info) do
        print(string.format('%20s, %s', k, v))
    end
end

myfun()

可以看到getinfo获取了诸如函数名,文件名,定义行等信息。

获取局部变量的函数:

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

此函数返回在栈的 f 层处函数的索引为 local 的局部变量 的名字和值。 这个函数不仅用于访问显式定义的局部变量,也包括形参、临时变量等。

local name, val
local function myfun(var)
    local a = 10
    local index = 1
    g = 108
    repeat
        name, val = debug.getlocal(1, index)
        print(index, name, val)
        index = index + 1
    until not name
end

myfun(100)

可以看出getlocal会从函数参数开始依次获取局部变量的值,直到为空。

当然我们也可以调用setlocal来改变局部变量,不过在实际的项目中好像并没有什么用,如果用setlocal改变局部变量,干嘛不直接在代码中改变局部变量呢。

setupvalue (f, up, value):

这个函数将 value 设为函数 f 的第 up 个上值。 如果函数没有那个上值,返回 nil 否则,返回该上值的名字。

关于函数的上值upvalue,简单的可以理解为函数引用的非局部变量。他这个变量也是可以获取并改变的。例如:

local function ch_up(f, name_, f_)
    local i = 1
    while true do  
        local name, value = debug.getupvalue(f, i)  
        if name == nil then  
            return false 
        end  
        if name == name_ then
            debug.setupvalue(f, i, f_)
            return true            
        end
        i = i + 1  
    end  
end

local function test()
    print('raw test')
end

local wrap_test = function()
    test()
end
wrap_test()
ch_up(wrap_test, 'test', function() print('new test') end)
wrap_test()

可以看到前后两次执行wrap_test()时,有不同的结果。

以上就是lua动态改变变量的理论基础,实际项目中还得灵活变通来热更新代码。



参考:

http://www.runoob.com/lua/lua-debug.html



### Lua热更新实现案例与示例代码 Lua热更新是一种在不中断程序运行的情况下,动态替换或重新加载模块的技术。以下是关于Lua热更新的实现方法和示例代码。 #### 热更新的基本原理Lua中,热更新通常通过重新加载模块并更新全局环境中的引用实现。以下是一个典型的热更新逻辑[^4]: 1. 将目标模块从`package.loaded`表中移除。 2. 使用`require`重新加载模块。 3. 更新旧模块中的键值对以确保所有引用都指向最新的实现。 #### 示例代码:Lua热更新实现 以下是一个完整的Lua热更新实现案例: ```lua -- test.lua module(..., package.seeall) function func(a, b) return a * b -- 初始实现为乘法 end ``` ```lua -- main.lua require "test" function mainloop() local ret = test.func(10, 10) print("Result:", ret) -- 输出结果 end function reload_module(module_name) local old_module = _G[module_name] package.loaded[module_name] = nil -- 移除已加载的模块 require(module_name) -- 重新加载模块 local new_module = _G[module_name] for k, v in pairs(new_module) do old_module[k] = v -- 更新旧模块的键值对 end package.loaded[module_name] = old_module -- 恢复到全局环境 end function reload() local modules_to_reload = {"test"} -- 需要热更新的模块列表 for _, module in ipairs(modules_to_reload) do reload_module(module) end end -- 测试热更新 mainloop() -- 调用初始版本的函数 -- 修改 test.lua 中的 func 函数为加法后保存文件 reload() -- 执行热更新 mainloop() -- 再次调用函数,验证热更新是否生效 ``` #### 运行流程说明 1. 初始状态下,`test.lua`中的`func`函数实现为乘法(`a * b`)。 2. 调用`mainloop`函数,输出结果为`100`。 3. 修改`test.lua`中的`func`函数实现为加法(`a + b`),并保存文件。 4. 调用`reload`函数执行热更新。 5. 再次调用`mainloop`函数,输出结果为`20`,证明热更新成功。 #### 注意事项 - 热更新时需要确保所有引用该模块的地方都被正确更新,否则可能导致程序行为异常。 - 在复杂项目中,建议结合调试工具(如EmmyLua)进行开发和测试[^3]。 #### 参考项目 如果需要更复杂的热更新方案,可以参考以下项目: - `lua_hotupdate`项目提供了Lua热更新的完整实现案例[^1]。 - 项目地址:[https://gitcode.com/gh_mirrors/lu/lua_hotupdate](https://gitcode.com/gh_mirrors/lu/lua_hotupdate) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值