Lua中的函数环境、_G及_ENV

lua5.1中的全局环境变量

Lua将环境table保存在一个全局变量_G中,可以对其访问和设置。一般我们把需要被访问的对象和函数等放到这里,
然后我们可以在需要时通过它来访问和使用。
可以通过value = _G["varname"]或者value = _G.varname来获得动态名字的全局变量。

> a=1
> b= "b"
> print(_G[a])
nil
> print(_G["a"])
1
> print(_G["b"])
b
> print(_G.a)
1
> print(_G.b)
b

“环境”是全局的,任何对它的修改都会影响程序的所有部分。对简单的使用不会有什么问题,但较复杂的应用,这个会是一大潜在的问题

Lua5.1中改变环境 - setfenv

Lua5.1允许每个函数拥有一个子集的环境来查找全局变量,可以通过setfenv来改变一个函数的环境,
第一个参数若是1则表示当前函数,2则表示调用当前函数的函数(依次类推),第二个参数是一个新的环境table。

比如下面,修改了函数的环境, print不存在了,再访问就会出错。

va = 1  
setfenv(1, {})  
print(va) -- 会报错,print是一个nil。这是因为一旦改变环境,所有的全局访问都会使用新的table  

为了避免上述问题,可以使用
setfenv(1, {_G = _G})将原来的环境保存起来,然后用_G.print来引用。

另一种组装新环境的方法是使用继承,下面的代码新环境从源环境中继承了print和a,任何赋值都发生在新的table中。

a = 1  
local newgt = {}  
setmetatable(newgt, {__index = _G})  
setfenv(1, newgt)  
print(a)  

或者

a = 1
local newgt = {}
setmetatable(newgt, {__index = _G})

示例:

a = "1"   -- create a global variable
print(a, getmetatable(a))
local t ={}
setmetatable(t, {__index = _G})
setfenv(1, t)   -- 设置当前的func-env为t
print(a)

----
_G.print("_G:", a)  --  _G:     1
t.print("t: ", a)   --  t:      1


setfenv(a, {})  -- change current environment to a new empty table
print(a)    -- attempt to call global 'print' (a nil value)

Lua5.1之后的环境

在5.2之后, 引入了_ENV叫做环境,与_G全局变量表产生了一些混淆。
在5.2中, 操作a = 1相当于_ENV['a'] = 1

这是一个最基础的认知改变,其次要格外注意_ENV不是全局变量,而是一个upvalue(非局部变量)。
其次,_ENV[‘_G’]指向了_ENV自身,这一目的是为了兼容5.1之前的版本,因为之前你也许会用到:
_G['a'] = 2, 在5.2中, 这相当于_ENV[‘_G’][‘a’],为了避免5.1之前的老代码在5.2中运行错误,所以5.2设置了_ENV[‘_G’]=_ENV来兼容这个问题。然而你不要忘记_ENV[‘_G’]=_ENV,所以一切都顺理成章了。

> a = 1
> _ENV[a]
nil
> _ENV["a"]
1
> _ENV["_G"]
table: 0x7fab5c5002e0
> print(_ENV)
table: 0x7fab5c5002e0
> 
> _G["a"]
1
> _ENV._G.a
1
> _ENV["_G"].a
1
> _ENV["_G"]["a"]
1
> 

在5.1中,我们可以为一段代码块(或者函数)设置环境,使用函数setfenv,这样会导致那一段代码/数访问全局变量的时候使用了setfuncs指定的table,而不是全局的_G。

在5.2中,setfenv遭到了废弃,因为引入了_ENV。 通过在函数定义前覆盖_ENV变量即可为函数定义设置一个全新的环境,比如:

a = 3
function echo()
    local _ENV={print=print, a = 2}

    function _echo()
        _ENV.print(a)
    end

    return _echo;       

end

print(a)        -- 3

---- 
local newEcho = echo()
print(newEcho)  -- function: 0x7fd1b94065c0
newEcho()       -- 2
  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值