全局变量_G有多特殊?
2020-6-20 9:12:55
收藏:0
阅读:81
评论:0
摘自Lua 5.3手册:
_G
全局变量(非函数),用于持有全局环境(参阅§2.2)。Lua 本身并不使用此变量;改变它的值不会影响任何环境,反之亦然。
§2.2 中相关的部分
[…] 每个代码块都是在命名为
_ENV的外部局部变量的作用域中编译的,所以_ENV自身在代码块中永远不是自由变量。[…]
_ENV的任何表都称为环境。Lua 保留着一个特殊的全局环境(称作
_G)在 C 注册表中。在 Lua 中,全局变量_G和它相同。 (_G在内部从未使用过.)当 Lua 加载代码块时,其
_ENV的默认值为全局环境。因此,默认情况下,Lua 代码中的自由变量引用全局环境中的条目。
我理解每个代码块加载时,由于 _ENV 是第一个 upvalue,它被指向由 load 指向的全局环境表。
> =_G, _ENV
table: 006d1bd8 table: 006d1bd8
确认二者指向同一张表。手册中反复说明,_ENV 和 _G 只是普通的变量名,没有任何隐含含义,Lua 本身也不使用它们。我尝试了下面的代码块:
local a = { }
local b = a -- 因为 table 是对象,两者都引用同一张表
print(a, b) -- 相同的地址打印了两次
a = { } -- 将其之一指向新构造的表
print(a, b) -- 打印新旧表地址
现在用 _G 和 _ENV 做相同的事情:
local g = _G -- 做一次额外的引用
print(g, _G, _ENV) -- 打印三次相同的地址
local p = print -- 备份 print 以供后用
_ENV = { } -- 将 `_ENV` 指向一个新表 / 环境
p(g, _G, _ENV) -- 旧, nil, 新
table: 00ce1be0 table: 00ce1be0 table: 00ce1be0
table: 00ce1be0 nil table: 00ce96e0
如果 _G 是一个普通全局变量,为什么它在这里成为了 nil?如果做了引用计数,那么当 _ENV 释放的时候,_G 仍然持有一个引用。与 b 一样,它也应该继续保持对旧表的引用,不是吗?
然而,对于下面的代码块,_G 保持不变/保留!
_ENV = { _G = _G }
_G.print(_G, _ENV, _ENV._G) -- 旧, 新, 旧
但是在这里它被删除了:
_ENV = { g = _G }
_ENV.g.print(_ENV, _ENV.g, _G) -- 新, 旧, nil
另一种情况下它是被保留的:
print(_G, _ENV) -- 相同的地址打印两次
local newgt = {} -- 创建新环境
setmetatable(newgt, {__index = _G}) -- 设置 metatable 为 _G 的 __index 元方法
_ENV = newgt -- 将 _ENV 指向 newgt
print(_G, newgt, _ENV) -- 旧, 新, 新
由于 _G 行为的变化如此之多,手册中最初的安慰显得不太可靠。我在这里漏掉了什么?
点赞
评论区的留言会收到邮件通知哦~
推荐文章
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法