Lua - __newindex元方法用于现有索引?
最近我了解了Lua中methatables的存在,并尝试使用它们来避免表中的“重复项”。我一直在寻找相关信息,但是一直没有发现我需要的东西,所以我来请求帮助。
- 我想要做的事情及其目的:
这是用于开发WoW插件的。 我希望创建一个工具,可以在创建变量或函数时在全局范围内弹出警告。因为可能会发生其他插件的命名冲突,所以需要避免使用全局范围。从那里开始,我还希望重定向所有与_G表的转移。因此,当用户在全局范围内创建变量或函数时,工具将捕获该值,将其存储在一个表中而不是_G中,并且每当用户尝试从_G中访问任何内容时,工具将首先在该表中查找它,仅在垫底线_G中找不到时才会使用_G。 因此,用户无需担心正确的封装或命名,工具会为其处理所有内容。
- 我已经成功完成的事情:
我正在_G上设置__newindex元方法来捕获全局作用域的变量和函数,并在插件加载结束时删除该元方法,以避免其他插件使用它。 对于_G转移的“间接”,我已经知道如何使用__index来尝试在尝试使用_G之前给出另一个表中存储的值。
- 我遇到的问题:
这可以很好地工作,但仅适用于_G中不存在的变量和函数。每当为_G表中已存在的键分配值时,它无法工作(由于明显的原因)。我希望能够捕获这些情况,基本上使其不可能实际上覆盖_G的内容,而是使用一种类似于“重载”的方式(但用户甚至不必知道)。
- 我尝试过的方法:
我尝试挂钩rawset,看它是否会自动调用,但它似乎没有。
我没有找到关于Lua中_G表的详细说明,主要是因为它的短名称。我肯定有某些信息可以帮助我实现想要的功能,但目前我有点迷失和失望。 所以,我想知道是否有任何方法可以“捕获”所有“隐式调用rawset”,以便在让它完成其工作之前进行一些检查。我收集到的信息是似乎没有__existingindex的元方法,您知道如何做到这一点吗?
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?

虽然您已经在评论中得到了答案,但是在 Lua 5.1 中有关于“环境”更深入的概念。环境是一个附加到函数的表格,该函数将其“全局”读写重定向到此表格。
_G只是对“全局”环境的引用,即主线程(主协程)的环境。它可以被清除为nil而没有非明显的影响,因为它只是一个变量,类似于T = { }; T._T = T。特别地,
_G == getfenv(0),除非有人更改它的含义(参见 getfenv() 参考其参数为何)。当脚本被加载时,它隐式绑定到全局环境。由于 Lua 的顶层范围(又称为主块)只是一个匿名函数,因此其环境可以随时重新绑定到任何其他表:-- x.lua local T = { } local shadow = setmetatable({ }, { __index = getfenv(0) }) local mt = { __index = shadow, __newindex = function (t, k, v) -- while T is empty, this will be called every time you 'set global' -- do whatever you want here shadow[k] = v print(tostring(k)..' is set to '..tostring(v)) end } setmetatable(T, mt) -- T[k] goes to shadow, then to _G setfenv(1, T) -- change the environment of this module to T hello = "World" -- 'hello is set to World' print(T.hello) -- 'World' print(_G.hello) -- 'nil', because we didn't even touch _G hello = 3.14 -- 'hello is set to 3.14' hello = nil -- 'hello is set to nil' hello = 2.72 -- 'hello is set to 2.72' function f() -- 'f is set to function: 0x804a00' print(hello) end f() -- '2.72' assert(getfenv(f) == getfenv(1)) assert(getfenv(f) == T) setfenv(f, _G) -- return f back to _G f() -- 'nil'使用此方法,您可以完全隐藏其他模块的元表机制。请注意,在
setmetatable()调用之后更改mt不会产生任何效果。还要记住,
setfenv()下方定义的所有函数共享同一环境T(这不适用于通过require加载的外部函数/模块或从这些函数/模块返回的函数,因为环境继承是词法的)。将
__newindex设置为_G可能暂时有效,但要记住,在调用之间调用的任何函数可能尝试设置全局变量,这可能会干扰您的逻辑或以微妙的方式破坏它们的逻辑。发生冲突的可能性应该很低,因为破坏_G是一个坏主意,每个人都知道这一点。