Lua语言将全局环境自身保存在全局变量_G中,如下输出全局环境中所有全局变量的名称:
for n in pairs(_G) do print(n) end
- 具有动态名称的全局变量
全局变量在另一个变量中的获取,
value = load("return"..varname)() 和
value = _G[varname] 相同效果,后者效率高出一个数量级。
- 全局变量声明
全局变量不需声明就可以使用,检测所有全局表不存在的访问,如下:
setmetatable(_G,{
__newindex = function (_,n)
error("attempt to write to undeclared varibale "..n,2)
end,
__index = function (_,n)
error("attempt to read to undeclared varibale "..n,2)
end,
})
当然可以使用rawset,rawget绕过元方法。
- 非全局变量
自由名称(free name)如:x 等价于 _ENV.x,_ENV本身是一个局部变量,是任意表,称为一个环境。
Lua处理全局变量的方式:
编译所有代码前,在外层创建局部变量_ENV;
所有自由名称var变换为_ENV.var;
函数load使用全局环境初始化代码段的第一个上值,即lua语法内部维护的一个表。
- 使用_ENV
代码段(一个文件)都有一个_ENV变量。_ENV = nil 会使后续代码不能直接访问全局变量。_ENV主要用途是改变代码段使用的环境。使用继承把旧环境装入如下:
local newgt = {}
setmetatable(newgt, {__index = _G})
_ENV = newget
任何赋值都发生在新表中。只能通过_G来修改全局变量中的变量。
- 环境和模块
_ENV解决污染全局变量。
- _EVN和load
load通常把加载代码段上值_ENV初始化为全局环境,还有一个可选参数为_ENV指定不同初始值。
env = {}
loadfile("config.lua","t",env)()
类似运行在沙盒中。
重复运行一段代码数次,每次不同环境,两种选择如下:
第一种使用debug.setupvalue(f,1,env)
第一个参数是指定函数,第二参数是上值索引(永远是1),第三参数是新上值。【依赖调试库,打破可见性规则】
另一种,每次加载代码段对其修改,如下:
lua把所有代码段当做可变长参数函数进行编译,多出来这一行会把传给代码段的第一个参数赋值给_ENV,从而改变环境。
prefix = "_ENV = ...;"
f = loadwithprefix(prefix,io.lines(filename,"*L"))
...
env1 = {}
f(env1)
env2 = {}
f(env2)
来源:oschina
链接:https://my.oschina.net/u/4365856/blog/3275068