深度学习Lua--环境表

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)

猜你喜欢

转载自blog.csdn.net/Momo_Da/article/details/105598511