Lua非全局的环境

非全局的环境

全局环境的一个问题是,任何修改都会影响你的程序的所有部分。例如,当你安装一个 metatable 去控制全局访问时,你的整个程序都必须遵循同一个指导方针。如果你想使用标准库,标准库中可能使用到没有声明的全局变量,你将碰到坏运。

Lua 5.0 允许每个函数可以有自己的环境来改善这个问题,听起来这很奇怪;毕竟,全局变量表的目的就是为了全局性使用。然而在 Section 15.4 我们将看到这个机制带来很多有趣的结构,全局的值依然是随处可以获取的。
可以使用 setfenv 函数来改变一个函数的环境。Setfenv 接受函数和新的环境作为参数。除了使用函数本身,还可以指定一个数字表示栈顶的活动函数。数字 1 代表当前函数,数字 2 代表调用当前函数的函数(这对写一个辅助函数来改变他们调用者的环境是很方便的)依此类推。下面这段代码是企图应用 setfenv 失败的例子:

a = 1 -- create a global variable 
-- change current environment to a new empty table 
setfenv(1, {}) 
print(a) 
导致:
stdin:5: attempt to call global `print' (a nil value) 

(你必须在单独的 chunk 内运行这段代码,如果你在交互模式逐行运行他,每一行都是一个不同的函数,调用 setfenv 只会影响他自己的那一行。)一旦你改变了你的环境,所有全局访问都使用这个新的表,如果她为空,你就丢失所有你的全局变量,甚至_G,所以,你应该首先使用一些有用的值封装(populate)她,比如老的环境:

a = 1 -- create a global variable 
-- change current environment 
setfenv(1, {_G = _G}) 
_G.print(a) --> nil 
_G.print(_G.a) --> 1 
现在,当你访问"global" _G,他的值为旧的环境,其中你可以使用 print 函数。你也可以使用继承封装(populate)你的新的环境:
a = 1 
local newgt = {} -- create new environment 
setmetatable(newgt, {__index = _G}) 
setfenv(1, newgt) -- set it 
print(a) --> 1 

在这段代码新的环境从旧的环境中继承了 print 和 a;然而,任何赋值操作都对新表进行,不用担心误操作修改了全局变量表。另外,你仍然可以通过_G 修改全局变量:

-- continuing previous code 
a = 10 
print(a) --> 10 
print(_G.a) --> 1 
_G.a = 20 
print(_G.a) --> 20 

当你创建一个新的函数时,他从创建他的函数继承了环境变量。所以,如果一个chunk 改变了他自己的环境,这个 chunk 所有在改变之后定义的函数都共享相同的环境,都会受到影响。这对创建命名空间是非常有用的机制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值