
Lua 的设计有一点很奇怪,在一个 block 中的变量,如果之前没有定义过,那么认为它是一个全局变量,而不是这个 block 的局部变量。这一点和别的语言不同。容易造成不小心覆盖了全局同名变量的错误。
一、 定义
Lua 中的局部变量要用 local 关键字来显式定义,不使用 local 显式定义的变量就是全局变量:
g_var = 1 -- global var
local l_var = 2 -- local var
二、 作用域
局部变量的生命周期是有限的,它的作用域仅限于声明它的块(block)。一个块是一个控制结构的执行体、或者是一个函数的执行体再或者是一个程序块(chunk)。我们可以通过下面这个例子来理解一下局部变量作用域的问题:
x = 10
local i = 1 -- 程序块中的局部变量 i
while i <=x do
local x = i * 2 -- while 循环体中的局部变量 x
print(x) -- output: 2, 4, 6, 8, ...
i = i + 1
end
if i > 20 then
local x -- then 中的局部变量 x
x = 20
print(x + 2) -- 如果i > 20 将会打印 22,此处的 x 是局部变量
else
print(x) -- 打印 10,这里 x 是全局变量
end
print(x) -- 打印 10
** 使用局部变量的好处**
1. 局部变量可以避免因为命名问题污染了全局环境
2. local 变量的访问比全局变量更快
3. 由于局部变量出了作用域之后生命周期结束,这样可以被垃圾回收器及时释放
在 Lua 中,应该尽量让定义变量的语句靠近使用变量的语句,这也可以被看做是一种良好的编程风格。在 C 这样的语言中,强制程序员在一个块(或一个过程)的起始处声明所有的局部变量,所以有些程序员认为在一个块的中间使用声明语句是一种不良好地习惯。实际上,在需要时才声明变量并且赋予有意义的初值,这样可以提高代码的可读性。
“尽量使用局部变量”是一种良好的编程风格。
Lua 上下文中应当严格避免使用自己定义的全局变量。
可以使用一个 lj-releng 工具来扫描 Lua 代码,定位使用 Lua 全局变量的地方。
三 栗子
foo.lua 文件
local _M = { _VERSION = '0.01' }
function _M.add(a, b) --两个number型变量相加
return a + b
end
function _M.update_A() --更新变量值
A = 365
end
return _M
** use_foo.lua 文件**
A = 360 --定义全局变量
local foo = require("foo")
local b = foo.add(A, A)
print("b = ", b)
foo.update_A()
print("A = ", A)
**输出结果: **
# luajit use_foo.lua
b = 720
A = 365
无论是做基础模块或是上层应用,肯定都不愿意存在这类灰色情况存在,因为它对我们系统的存在,带来很多不确定性(注意 OpenResty 会限制请求过程中全局变量的使用)。 生产中我们是要尽力避免这种情况的出现。