我最近在lua中了解到了美沙酮的存在,我一直在玩弄它们,直到我想到了一个想法:是否有可能使用那些试图避免"重复"在桌子上?我搜索和搜索,到目前为止无法找到我正在寻找的东西,所以我在这里。
它将用于魔兽插件编程。 我想创建一个工具,在全局范围内创建变量或函数时会提示警告(以避免使用它,因为可能与其他插件发生命名冲突)。 我可以从那里做的另一件事是将所有传输重定向到_G表。因此,当用户在全局范围内创建变量或函数时,该工具会捕获它,将其存储在表中而不是_G中,并且每当用户尝试从_G访问某些内容时,该工具将首先在所述中查找它表;并仅将_G用作后备。 这样,用户将无法担心正确的封装或命名,该工具将为他完成所有这些工作。
我在_G上设置一个__newindex元方法来捕获全局范围的变量和函数,并在插件加载结束时删除元方法,以避免被其他插件使用。 对于_G transit"的间接,我已经知道如何在尝试使用_G之前使用__index尝试将值存储在另一个表中。
这很有效,但只适用于_G中不存在的变量和函数。每当为一个已经在_G表中的键赋值时,它就不起作用(出于显而易见的原因)。我确实能够捕获这些情况,并且基本上不可能实际覆盖_G的内容,而是使用一种"重载" (但用户甚至不知道)。
我试图挂钩rawset,看它是否被自动调用,而且看起来不是。
我还没有找到关于lua中_G表的大量文档,因为主要是短名称。我确定某些东西必须存在于某个地方,我可能会利用这些信息按照我想要的方式完成工作,但目前我只是有点迷失并且没有想法。 所以,是的,我想知道是否有任何方式来抓住"所有"隐式调用rawset"为了在让它做它的东西之前进行一些检查。我收集到了显然没有__existingindex或其他东西的元方法,所以你知道有什么方法可以吗?
答案 0 :(得分:1)
虽然您在评论中得到了答案,但Lua 5.1中对环境有更深刻的概念。环境是一个附加到功能的表,其中该功能重定向其全局'读写。 _G
只是对全球'的引用。环境,即主线程(主协程)的环境。它可以被清除为零而没有非明显的效果,因为它只是一个变量,类似于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'
使用这种方法,您可以完全隐藏其他模块中的元化机制。请注意,mt
调用后对setmetatable()
的更改无效。
另请注意,setfenv()
下面定义的所有函数共享相同的环境T
(不适用于通过require
加载的外部函数/模块或从这些函数返回的/模块,因为环境继承是词汇的。)
暂时在__newindex
上设置_G
可能有效,但请记住,您之间调用的任何函数都可能尝试设置全局变量,这可能会干扰您的逻辑或以微妙的方式破坏它们。碰撞的可能性应该很低,因为破坏_G
是一个坏主意,每个人都知道。