如何在Lua函数作用域内通过setfenv重写package.loaded表?
问题解决:setfenv重写package.loaded无效的问题
你遇到的核心问题是:直接引用的全局require函数运行在全局环境中,它会读取全局的package表,而非你自定义环境里的package,所以你在env里定义的package.loaded完全没被用到。
解决方案:让require使用自定义环境的package
有两种可行的实现方式:
方式1:自定义require函数
在自定义环境中实现一个仅依赖当前环境package的require,逻辑和原生require对齐(先检查loaded,再处理preload等),示例代码:
local env = { print = print, package = { cpath = package.cpath, loadlib = package.loadlib, path = package.path, preload = package.preload, seeall = package.seeall, loaded = { foobar = { fn = function() print("hello world") end, }, }, }, } -- 自定义require,优先读取当前环境的package.loaded env.require = function(modname) -- 检查是否已加载 local loaded_mod = env.package.loaded[modname] if loaded_mod then return loaded_mod end -- 如需完整模拟原生require,可补充preload、路径查找等逻辑 error("module '" .. modname .. "' not found") end -- 执行测试代码 setfenv(assert(loadstring("local fb = require('foobar'); fb.fn()")), env)()
方式2:修改原生require的环境
复制全局require并修改其运行环境为自定义env,这样它会自动读取env里的package,示例代码:
local env = { print = print, package = { cpath = package.cpath, loadlib = package.loadlib, path = package.path, preload = package.preload, seeall = package.seeall, loaded = { foobar = { fn = function() print("hello world") end, }, }, }, } -- 复制原生require并修改其环境为自定义env local custom_require = require setfenv(custom_require, env) env.require = custom_require -- 执行测试代码 setfenv(assert(loadstring("local fb = require('foobar'); fb.fn()")), env)()
两种方式都能让require读取你自定义的package.loaded,执行后会正常打印hello world。
内容的提问来源于stack exchange,提问作者Kyle Richards
相关产品推荐
相关产品推荐

