非全局环境

简介: 非全局环境

Lua 语言中,全局变量并不一定非得是真正全局的。 Lua 语言甚至根本没有全局变量。由于我们在平时不断地使用全局变量,所以一开始听上去这可能很诡异。 Lua 语言竭尽全力地让程序员具有全局变量存在的幻觉。现在,让我们看看 Lua 语言是如何构建这种幻觉的。


提示

这种机制是 Lua5.1Lua5.2 之间改变最大的部分,接下来的讨论基本都不适用与 Lua5.1


首先,让我们忘掉全局变量而从自由名称的概念开始讨论。一个自有名称是指没有关联到显式声明上的名称,即它不出现在对应局部变量的范围内。例如,在下面的代码中, xy 是自由名称,而 z 则不是:

local z = 10
x = y + z


接下来就到了关键的部分: Lua 语言编译器将代码段中的所有自由名称 x 转换为 _ENV.x 。因此,此前的代码段完全等价于:

local z = 10
_ENV.x = _ENV.y + z


但是这里新出现的 _ENV 变量由究竟是什么呢?


我们刚刚才说过, Lua 语言中没有全局变量。因此 _ENV 不可能是全局变量。在这里,编译器实际上又进行了一次巧妙的工作。 Lua 语言把所有的代码段都当做匿名函数。所以, Lua 语言编译器实际上将原来的代码段编译为如下形式:

local _ENV = some value (某些值)
return function (...)
  local z = 10
  _ENV.x = _ENV.y + z
end


也就是说, Lua 语言是在一个名为 _ENV 的预定义上值(一个外部的局部变量, upvalue )存在的情况下编译所有的代码段的。因此,所有的变量要么是绑定到了一个名称的局部变量,要么是 _ENV 中的一个字段,而 _ENV 本身是一个局部变量(一个上值)。


_ENV 的初始值可以是任意的表(实际上也不用一定是表)。任何一个这样的表都被称为一个环境。为了维护全局变量存在的幻觉, Lua 语言在内部维护了一个表用来做全局环境。通常,当加载一段代码时,函数 load 会使用预定义的上值来初始化全局环境。因此,原始的代码等价于:

local _ENV = the global environment (全局环境)
return function (...)
  local z = 10
  _ENV.x = _ENV.y + z
end


上述赋值的结果是,全局环境中的字段 x 得到全局环境中字段 y10 的结果。


咋一看,这可能像是操作全局变量的一种相当拐弯抹角的方式。但是,这种方式比那些更简单的实现方法具有更多的灵活性。


我们先总结一下 Lua 语言中处理全局变量的方式:

  • 编译器在编译所有代码段前,在外层创建局部变量_ENV
  • 编译器将所有自由名称var变换为_ENV.var
  • 函数load或函数loadfile使用全局环境初始化代码段的第一个上值,即Lua语言内部维护的一个普通表。


实际上,这也不是太复杂。


有些人由于试图从这些规则中引申出额外的“魔法”而感到困惑,其实,这些规则并没有额外的定义。尤其是,前两条规则完全是由编译器进行的。除了是编译器预先定义的, _ENV 只是一个单纯的普通变量。抛开编译器,名称 _ENV 对于 Lua 语言来说根本没有特殊含义。类似的,从 x_ENV.x 的转换是纯粹的语法转换,没有隐藏的含义。尤其是,在转换后,按照标准的可见性规则, _ENV 引用的是其所在位置所有可见的 _ENV 变量。


提示

Lua 语言将 _ENV 用于错误信息,以便与能够像报告涉及 global x 的一个错误一样报告涉及变量 _ENV.x 的错误。

目录
相关文章
|
4月前
自动检查以确保依赖项始终与使用的electron版本相匹配的小技巧
自动检查以确保依赖项始终与使用的electron版本相匹配的小技巧
23 0
|
4月前
|
编译器 C# 开发者
C# 10.0中的全局`using`指令:简化命名空间引用的新方式
【1月更文挑战第4天】本文介绍了C# 10.0中引入的全局`using`指令,该指令允许开发者在项目级别统一管理命名空间引用,从而消除源文件中重复的`using`语句。全局`using`指令通过减少冗余代码、提高可维护性和统一命名空间管理,为开发者带来了更高效的编码体验。文章详细解释了如何实现全局`using`指令,并探讨了其在实际项目中的优势和适用场景。
|
10月前
|
数据可视化 Java 开发工具
如何比较同一个项目中不同版本的区别
如何比较同一个项目中不同版本的区别
137 0
|
存储 NoSQL 算法
【实战场景一】设计一个分布式环境下全局唯一的信号器
如何正确设计一个分布式环境下全局唯一的信号器?
131 0
|
小程序 JavaScript
【小程序】全局数据共享
【小程序】全局数据共享
185 0
【小程序】全局数据共享
|
算法 数据库 芯片
SRIO系统初始化过程和路由配置
SRIO系统初始化过程和路由配置
298 0
|
Kubernetes 网络协议 API
关于K8s中 pod 资源使用全局、局部限制 的一些笔记
写在前面 分享一些 K8s 中 LimitRange 的笔记 博文内容涉及: LimitRange 简单介绍 LimitRange 资源对象创建使用 准入检查和资源约束的一些 Demo 理解不足小伙伴帮忙指正
354 0
|
C++
配置 C 和 C++ 环境
配置 C 和 C++ 环境
101 0
|
程序员
环境和模块
环境和模块
74 0
根据不同环境需求来选择合适的光模块?
随着信息化的高速发展,光通信应用已经越来越普及,大到远距离的高速骨干网、小到光纤宽带入户,光纤凭借大容量高速传输优势愈来愈发挥着更大的作用。有光纤的地方就离不开光模块,光模块的选择选购也成为一线工程技术人员或者采购人员关注的问题。
1467 0