Lua Global环境

Lua的全局变量实际上是用environment这个表来存储所有的全局变量,其优点就是简化了lua的内部实现,而且还能像其他类型的表一样去操作这个全局表。

_G

Lua将environment本身存储在全局变量_G中,其中_G._G = _G。如若感兴趣,可以直接用pairs函数打印当前的全局变量名:

Lua 复制代码
A = {1,2,3}

function testMySelf()
end

for n in pairs(_G) do print(n) end
--[[
assert
dofile
...
testMySelf
utf8
A
package
...
pairs
_G
...
]]--

_G的用法其实和直接赋值全局变量差不多,如下两句性质完全一样的代码所示:

Lua 复制代码
_G["a"] = _G["var1"]
a = var1

getfield/setfield

手动写一个getfield函数,用以通过字符串查找相应的域,比如a.b.c.d的值是多少。实际上是从_G开始循环向域内部遍历:

Lua 复制代码
function getfield (f) 
    local v = _G -- start with the table of globals 
    for w in string.gmatch(f, "([%w_]+)") do
     v = v[w]
    end
    return v
end

A = {["a"] = 1}
print(getfield("A.a")) --1

setfield也是一样的道理,只不过需要判断是否是最后一个".",需要独立处理最后一个域并进行赋值,比如A.a = 1:

Lua 复制代码
function setfield (f, v) 
    local t = _G -- start with the table of globals 
    for w, d in string.gmatch(f, "([%w_]+)(.?)") do
        if d == "." then -- not last field? 
            t[w] = t[w] or {} -- create table if absent 
            t = t[w] -- get the table 
        else -- last field 
            t[w] = v -- do the assignment 
        end
    end
end

setfield("A.a",2)
print(A.a) --2

声明全局变量

如若控制全局变量的声明和访问,则直接控制_G的newindex和index即可,但是需要注意一点的是如果在newindex中明确禁止了全局变量的声明操作,那么任何直接赋值都是有问题的,如以下代码:

Lua 复制代码
setmetatable(_G, { 
    __newindex = function (_, n)
        print("attempt to write to undeclared variable "..n)
   end,
    __index = function (_, n)
        print("attempt to read undeclared variable "..n)
   end,
})
A = {} --attempt to write to undeclared variable A

这时候只能通过rawget/rawset来直接进行访问操作。比如声明一个入口函数,所有全局变量的声明都必须经此函数初始化;判断这个域是否存在,也需要用rawget函数直接访问:

Lua 复制代码
function declare (name, initval) 
 rawset(_G, name, initval or false) 
end

...
if rawget(_G, var) == nil then
-- 'var' is undeclared 
 ... 
end

当然需要注意的是上述处理中初始化全局变量如果是nil赋值则默认赋值为false了。

如若不需要这个默认赋值,希望代码支持类似a = nil的声明,那么也可以维护一个注册表并放入newindex元方法中判断,当然这也是官方文档给的一个解决方案(不过对本人来说觉得有点鸡肋,毕竟类似a = nil的代码是可以避免的):

Lua 复制代码
local declaredNames = {}
function declare (name, initval)
    rawset(_G, name, initval)
    declaredNames[name] = true
end
setmetatable(_G, {
    __newindex = function (t, n, v)
    if not declaredNames[n] then
        error("attempt to write to undeclared var. "..n, 2)
    else
        print("newindex")
        rawset(t, n, v) -- do the actual set 
    end
    end,
    __index = function (_, n)
        if not declaredNames[n] then
            error("attempt to read undeclared var. "..n, 2)
        else
            return nil
        end
    end,
})

declare("A",nil)
A = {} --newindex
相关推荐
gCode Teacher 格码致知1 小时前
Pandas教学-17:Series与Dataframe的关系
开发语言·python·pandas
发量惊人的中年网工1 小时前
分公司访问总部ERP慢怎么办?SD-WAN组网的排查与验收要点
服务器·开发语言·php
下页、再停留1 小时前
【C#桌面客户端系列学习-15】生成可视化图表之折线图、柱状图、饼状图
开发语言·c#
ShineWinsu2 小时前
对于JavaScript:操作元素的解析
开发语言·前端·javascript·面试·web·dom·元素
益莱储中国3 小时前
深度解析:RF 实验室从 5G迈向 6G 的过程中保持技术领先与设备升级的路径
开发语言·php
benchmark_cc4 小时前
Python 量化系统如何设计统一的数据访问接口:从策略解耦到数据层架构
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
const_qiu4 小时前
第四章 00:开篇 —— 从「会聊天」到「记得住、会干活、能协作」
java·开发语言·人工智能·python
Wang's Blog4 小时前
Java 项目实战: 交友项目 - 个人资料管理的更新接口实现与坑
java·开发语言·交友
CoderYanger5 小时前
Java EE 进阶:4.Spring Web MVC 入门(第一弹)
java·开发语言·前端·spring·面试·java-ee·mvc
估值探索者5 小时前
【Python量化选股流水线 #04】选股器好不好用?「昨日候选→今日表现」回看验收
开发语言·python·股票数据·股票数据api接口