每个被编译的Lua代码块都会有一个外部的局部变量叫做_ENV
,因此,_ENV
这个名字永远都不会成为一个代码块中的自由名字。在转译自由名字时,_ENV
是否是那个外部的局部变量无所谓。_ENV
和其他变量名没有区别。你可以定义一个新变量或指定一个参数叫做此名字。当编译器在转译自由名字时所用到的_ENV
,指的是你的程序在那个点上可见的名为_ENV
的变量。另外,被_ENV
用于值的那张表被称为环境。
Lua环境由所有可操作的数据构成,如编译好的函数、变量、运行时内存。这些数据保存在一个称为lua_State
的结构中。所有Lua应用程序都必要求至少有一个lua_State
,如果需要还可以有多个,如需要为不同的系统保存不同的数据时。
对开发者来说,Lua环境是用来发送和接收数据的地方,它利用栈(Lua Stack)来达到该目的。Lua栈不同于系统栈,它只能通过Lua的API函数访问。
Lua在运行时创建变量并将其保存在环境中,Lua语言支持很多类型,重点用在C++代码中有三个:字符串、数字、函数。表和用户数据这样复杂的数据结构,最好还是只在Lua代码中使用。
Lua保有一个被称为全局环境的特别环境,它被保存在C
注册表的一个特别的索引下。在Lua中,全局变量_G
被初始化为这个值(_G
不被内部任何地方使用)。Lua将所有全局变量_G
都保存在一个“环境(environment)”的表中,其优点在于:
- 无需再为全局变量创建新的数据结构,简化了内部实现。
- 直接使用表的方式来操作环境
当Lua加载一个代码块,_ENV
上值的默认值就是全局环境。默认情况下,Lua代码中提及的自由名字都指的是全局环境中的相关项目(全局变量)。此外,所有标准库都被加载到全局环境,一些函数也针对这个环境做操作。可使用load
或loadfile
加载代码块,并赋予它们不同的环境。
for k,v in pairs(_G) do
print(k, v)
end
rawget function: 0000000061d18bd0
loadfile function: 0000000061d19440
rawset function: 0000000061d18b70
dofile function: 0000000061d19510
type function: 0000000061d18780
getmetatable function: 0000000061d194b0
math table: 0000000000d79730
_VERSION Lua 5.3
tostring function: 0000000061d18860
pcall function: 0000000061d187e0
setmetatable function: 0000000061d19110
rawlen function: 0000000061d18c20
xpcall function: 0000000061d186e0
debug table: 0000000000d798f0
coroutine table: 0000000000d790f0
collectgarbage function: 0000000061d19040
tonumber function: 0000000061d18930
assert function: 0000000061d19590
error function: 0000000061d18fb0
pairs function: 0000000061d19280
arg table: 0000000000d79770
next function: 0000000061d18e30
bit32 table: 0000000000d799f0
utf8 table: 0000000000d794b0
string table: 0000000000d79970
print function: 0000000061d18cd0
os table: 0000000000d79430
io table: 0000000000d797f0
table table: 0000000000d790a0
require function: 0000000000d78ea0
load function: 0000000061d19340
_G table: 0000000000d76e00
package table: 0000000000d78ef0
select function: 0000000061d18890
rawequal function: 0000000061d18c80
ipairs function: 0000000061d192a0
-- for k,v in pairs(_G) do
-- print(k, v)
-- end
function getGlobal(key)
local g = _G
for k in string.gmatch(key, "[%w_]+") do
g = g[key]
end
return g
end
function setGlobal(key, val)
local g = _G
for k,v in string.gmatch(key, "([%w_]+)(%.?)") do
if v=="." then
g[k] = g[k] or {}
g = g[k]
else
g[k] = val
end
end
end
-- print(getGlobal("error"))
-- print(_G["error"])
-- setGlobal("pi", 3.14)
-- print(getGlobal("pi"))
local global = {}
local mt = {}
mt.__index = function(_, key)
if not global[key] then
error("错误:试图访问未定义的变量"..key)
else
return rawget(_, key)
end
end
mt.__newindex = function(table, key, val)
if not global[key] then
local what = debug.getinfo(2, "S").what
print(what)
if what~="main" and what~="C" then
print(what)
error("错误:试图写入未定义的变量"..key)
end
global[key] = true
end
print("日志:设置全局变量"..key.."为"..val)
rawset(table, key, val)
end
setmetatable(_G, mt)
i = 100
function test()
l = 100
end