当前位置: 首页 > news >正文

Lua Global环境

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

_G

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

A = {1,2,3}function testMySelf()
endfor n in pairs(_G) do print(n) end
--[[
assert
dofile
...
testMySelf
utf8
A
package
...
pairs
_G
...
]]--

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

_G["a"] = _G["var1"]
a = var1

getfield/setfield

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

function getfield (f) local v = _G -- start with the table of globals for w in string.gmatch(f, "([%w_]+)") dov = v[w]endreturn v
endA = {["a"] = 1}
print(getfield("A.a")) --1

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

function setfield (f, v) local t = _G -- start with the table of globals for w, d in string.gmatch(f, "([%w_]+)(.?)") doif 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 endend
endsetfield("A.a",2)
print(A.a) --2

声明全局变量

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

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函数直接访问:

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的代码是可以避免的):

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] thenerror("attempt to write to undeclared var. "..n, 2)elseprint("newindex")rawset(t, n, v) -- do the actual set endend,__index = function (_, n)if not declaredNames[n] thenerror("attempt to read undeclared var. "..n, 2)elsereturn nilendend,
})declare("A",nil)
A = {} --newindex

相关文章:

  • 掌握rm命令:Linux文件删除的艺术与安全指南
  • 常见的Web前端开发框架推荐
  • 8868体育助力意甲国际米兰俱乐部 国米锁定意甲冠军
  • Leetcode - 周赛384
  • C++ //练习 6.11 编写并验证你自己的reset函数,使其作用于引用类型的参数。
  • 论文阅读:GamutMLP A Lightweight MLP for Color Loss Recovery
  • 【读书笔记】ICS设备及应用攻击(一)
  • 中断系统(单片机)
  • 杨中科 ASP.NET DI综合案例
  • OpenAI Sora 初体验
  • Android Compose 一个音视频APP——Magic Music Player
  • Arrays工具类的常见方法总结
  • 高校疫情防控系统的全栈开发实战
  • Day37 贪心算法part06
  • Acwing 周赛143 解题报告 | 珂学家 | 状压DP
  • [Vue CLI 3] 配置解析之 css.extract
  • 【面试系列】之二:关于js原型
  • angular学习第一篇-----环境搭建
  • HashMap剖析之内部结构
  • JavaScript 基础知识 - 入门篇(一)
  • JAVA多线程机制解析-volatilesynchronized
  • Java新版本的开发已正式进入轨道,版本号18.3
  • k8s如何管理Pod
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • PaddlePaddle-GitHub的正确打开姿势
  • Webpack 4 学习01(基础配置)
  • 如何打造100亿SDK累计覆盖量的大数据系统
  • 如何抓住下一波零售风口?看RPA玩转零售自动化
  • 深入浏览器事件循环的本质
  • 什么软件可以提取视频中的音频制作成手机铃声
  • 想写好前端,先练好内功
  • 学习笔记:对象,原型和继承(1)
  • 1.Ext JS 建立web开发工程
  • gunicorn工作原理
  • mysql面试题分组并合并列
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  • ()、[]、{}、(())、[[]]命令替换
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (7)STL算法之交换赋值
  • (js)循环条件满足时终止循环
  • (TipsTricks)用客户端模板精简JavaScript代码
  • (一)appium-desktop定位元素原理
  • (转)iOS字体
  • (转)mysql使用Navicat 导出和导入数据库
  • .Net CF下精确的计时器
  • .Net Core与存储过程(一)
  • .net wcf memory gates checking failed
  • .Net各种迷惑命名解释
  • @Autowired标签与 @Resource标签 的区别
  • @Mapper作用
  • [ JavaScript ] JSON方法
  • [ 云计算 | AWS ] AI 编程助手新势力 Amazon CodeWhisperer:优势功能及实用技巧
  • []常用AT命令解释()
  • [Angular 基础] - 指令(directives)