Lua环境

每个被编译的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代码中提及的自由名字都指的是全局环境中的相关项目(全局变量)。此外,所有标准库都被加载到全局环境,一些函数也针对这个环境做操作。可使用loadloadfile加载代码块,并赋予它们不同的环境。

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

具有动态名字的全局变量

猜你喜欢

转载自blog.csdn.net/weixin_34343308/article/details/87536023