Lua 学习 chapter22
目录
- 具有动态名称的全局变量
- 非全局环境
- 环境和模块
- _ENV和load
只有疯狂过,你才知道自己究竟能不能成功。
具有动态名称的全局变量
在lua中,所有的全局变量都被存在_G中,通过_G[name]可以访问到任意一个全局变量。在lua中,全局变量不需要声明就可以直接使用,但是这个可能会造成非常难以查询的bug,所以我们可以对全局变量进行简单的封装。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
setmetatable(_G, {
__newindex = function(_, n)
error("attempt to write to undeclared variable" .. n, 2)
end,
__index = function(_, n)
error("attempt to read undeclared variable" .. n, 2)
end
})
--这样我们怎么对全局变量初始化呢?使用rawset方法。
function declare(name, initval)
rawset(_G, name, initval or false)
end
–改版后的
local declaredNames = {}
setmetatable(G, {
__newindex = function(t, n, v)
if not declaredNames[n] then
local w = debug.getinfo(2, "S").what
if w ~= "main" and w ~= "C" then
error("attempt to write to undeclared variable" … n, 2)
end
declaredNames[n] = true
end
rawset(t, n, v)
end,
__index = function(, n)
if not declaredNames[n] then
error("attempt to read undeclared variable" … n, 2)
else
return nil
end
end
})
非全局环境
lua语言中处理全局变量的方式:
- 编译器在编译所有代码之前,在外层创建局部变量_ENV
- 编译器将所有自由名称变换为_ENV.var;
- 函数load(or loadfile)使用全局环境初始化代码段的第一个上值,即lua语言内部维护的一个普通表。
_ENV只是一个普通的变量,将其赋值为nil会使得后续的代码不能直接访问全局变量。
我们还可以使用_ENV来绕过局部声明的变量,直接访问全局变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
local print, sin = print, math.sin
_ENV = nil
print(13)
print(sin(13))
print(cos(13)) --error 访问不到全局
a = 13
local a = 12
print(a)
print(_ENV.a) –访问全局的a,当然也可以使用_G来访问全局的a
_ENV = {}
a = 1
print(a) –print is a nil
a = 15
_ENV = {g = _G}
a = 1
g.print(_ENV.a, g.a} – 1 , 15
通常_G和_ENV指向的是同一个表。但是,尽管如此,他们是很不一样的实体。_ENV是一个局部变量,所以对“全局变量”的访问实际上访问的都是_ENV。_G则是一个在任何情况下都没有任何特殊状态的全局变量。_ENV永远指向的是当前的环境;而假设在可见且无人改变过其值的前提下,_G通常指向的是全局变量。
_ENV的主要作用就是改变当前的环境。
环境和模块
为了防止污染全局环境:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
local M = {}
_ENV = {}
function hello()
print("hello")
end
function sayHello()
hello() –M.hello
end
local M = {}
local sqrt = math.sqrt
local in = io
_ENV = nil
–这样就不能进行外部访问了
load函数通常被加载代码段的上值_ENV初始化为全局变量。
_ENV和load
函数load通常把加载代码段的上值_ENV初始化为全局变量。不过,函数load还有一个可选的第四个参数来让我们为_ENV指定一个不同的初始值。
1
2
3
4
5
6
7
--file "config.lua"
width = 200
height = 100
–加载文件
env = {}
loadfile("config","t",env)()
配置文件中的代码会运行在空的环境env中,类似于某种沙盒。特别的,所有的定义都会进入这个环境中。即使出错,配置文件也无法影响任何别的东西。
<hr style="visibility: hidden;"/>
<hr style="visibility: hidden;"/>