局部变量和全局变量的比较
- 实现: 局部变量索引堆栈上的寄存器数组,使用硬编码的整数索引(至少在标准实现中 - LuaImplementations)。全局变量从一个表(或用户数据)中索引,通常使用变量名字符串作为键,存储为常量或变量。
- 注意:在 5.2.0work3 中,全局变量的概念仍然存在于语言中,但从 VM 中删除(没有特殊的 GETGLOBAL/SETGLOBAL 操作码)。从 VM 的角度来看,全局变量与从局部变量(实际上是词法闭包)表中的获取/设置没有区别。
- 注意:提升为闭包的局部变量在 VM 中的处理方式与普通局部变量略有不同。闭包通过特殊的 VM 操作码访问。
- 语法: 如果设置了环境表,则可以在 Lua 代码中访问全局变量,无论是否显式命名它们所属的环境表:
foo
、_G.foo
或 getfenv().foo
(或在 5.2.0work3 中,_ENV.foo
)。这允许不同的环境使用方式,例如在 ModuleDefinition 中。
- 作用域: 局部变量的作用域在词法块内。全局变量的作用域在运行时分配给给定环境表的任何数量的函数中。在 5.2.0work3 中,全局变量的作用域在运行时分配给给定环境表的任何数量的词法块中(在编译时声明,但在运行时分配)。
- 声明: 局部变量必须使用
local
语句显式声明才能使用。赋值默认情况下是全局的,而不是 LocalByDefault。全局变量可以即时访问,即使变量名在运行时设置(例如,“foo=io.stdin:read'*l'; return _G[foo]
”)。局部变量列表是静态定义的。全局变量列表可以在运行时确定,甚至可以在程序执行期间更改。
- 标准库访问: 标准库通常通过全局变量暴露给代码块。不过,另一种方法是显式地将 _G 或其元素作为局部参数传递,“
local _G, math, math_sqrt = ...
”,但这可能很繁琐。
- 优先级: 局部变量覆盖全局变量。即使全局变量具有更具体的范围,这一点仍然成立,因此在 5.2.0work3 中,“
local x = 1; do local _ENV = {x=2}; return x end
” 返回 1。
- 作用域传递: 通过传递环境表,可以将一组完整的全局变量或对全局变量的引用传递到不同的作用域。从某种意义上说,全局作用域是 Lua 中的“一等阀门”。局部变量不能像这样传递,除非创建包含显式引用的局部变量的闭包。一个例外是 debug.getlocal/setlocal,如 StringInterpolation 中所用,但这是一种技巧。
- 字节码内省: 全局变量在字节码中更可见。全局获取/设置变为带有给定变量名的 GETGLOBAL/SETGLOBAL 操作码。在 5.2.0work3 中,这些变为 GETTABUP/SETTABUP 操作码 [1]。可以列出编译后的块中读取或写入的所有全局变量,如 检测未定义变量 所用。
- 数量限制: 每个函数的局部变量数量有限制(MAXLOCALS,通常为 200)。
最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2010 年 7 月 10 日下午 10:35 GMT (差异)