LUA教程环境非全局的环境 -61

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所有在改变之后定义的函数都共享相同的环境,都会受到影响。这对创建命名空间是非常有用的机制,我们下一章将会看到。


发布日期:

所属分类: 编程 标签:


没有相关文章!