变量与作用域

3.1 变量声明

全局变量

在 Lua 中,不加 local 关键字声明的变量默认是全局变量

1
2
3
4
-- 全局变量
name = "Lua"
age = 30
print(name, age) --> Lua 30

即使是在循环或条件分支内部,不加 local 也是全局的:

1
2
3
4
for i = 1, 3 do
result = i * 2 -- 这里是全局变量!
end
print(result) --> 6(全局变量在循环外依然存在)

注意:全局变量不需要提前声明,未赋值的全局变量的值是 nil

局部变量

使用 local 关键字声明局部变量:

1
2
local name = "局部"
print(name) --> 局部

局部变量的作用域从声明位置开始,到所在的块(do...end、函数体、文件结尾)结束:

1
2
3
4
5
do
local x = 10
print(x) --> 10
end
print(x) --> nil(超出作用域)

变量命名建议

  • 尽量使用 local,避免全局变量污染
  • 函数内外都使用 local,提高性能(访问局部变量比全局变量快)
  • 全局变量只在需要模块导出时使用

3.2 多值赋值

Lua 支持一次性给多个变量赋值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- 基本多值赋值
local a, b, c = 1, 2, 3
print(a, b, c) --> 1 2 3

-- 变量个数多于值,多余的变量为 nil
local x, y, z = 10, 20
print(x, y, z) --> 10 20 nil

-- 值个数多于变量,多余的值被丢弃
local m, n = 1, 2, 3, 4
print(m, n) --> 1 2

-- 经典用法:交换两个变量
local a, b = 10, 20
a, b = b, a
print(a, b) --> 20 10

-- 函数多返回值赋值
function minmax(a, b)
if a < b then return a, b else return b, a end
end
local min, max = minmax(5, 3)
print(min, max) --> 3 5

3.3 作用域规则

作用域层级

Lua 的作用域以 do...end、函数体或文件为单位:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
local a = "文件级"      -- 文件作用域

do
local b = "块级" -- 块作用域

do
local c = "内层块"
print(a, b, c) --> 文件级 块级 内层块(内层可访问外层)
end

print(c) --> nil(外层不能访问内层)
end

print(b) --> nil

变量查找规则

访问变量时,Lua 按照以下顺序查找:

  1. 当前块的局部变量
  2. 外层块的局部变量
  3. 当前文件的局部变量
  4. 全局环境 _G 中的变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
local x = "全局局部"

do
local x = "块局部"
print(x) --> 块局部(优先访问最近的)

do
local x = "最内层"
print(x) --> 最内层
end

print(x) --> 块局部
end

print(x) --> 全局局部

3.4 全局环境 _G

Lua 将所有全局变量存储在一个名为 _G 的表中。你可以像操作普通表一样操作 _G

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 创建全局变量(通常方式)
myVar = 100

-- 通过 _G 访问
print(_G.myVar) --> 100
print(_G["myVar"]) --> 100

-- 通过 _G 动态创建全局变量
_G["dynamicVar"] = "动态创建"
print(dynamicVar) --> 动态创建

-- 遍历所有全局变量
for k, v in pairs(_G) do
print(k, v)
end

检查变量是否存在

1
2
3
4
5
6
7
8
if _G.myVar ~= nil then
print("myVar 存在")
end

-- 或者直接判断(nil 为假)
if myVar then
print("myVar 存在且不为 nil/false")
end

注意_G 本身也是一个全局变量,所以 _G._G == _G 成立。


3.5 局部变量与性能

性能差异

访问局部变量比全局变量快,因为局部变量直接存储在寄存器中,而全局变量需要查表:

1
2
3
4
5
6
7
-- 性能优化技巧:将频繁访问的全局函数缓存为局部变量
local print = print -- 缓存
local pi = math.pi

for i = 1, 1000000 do
print(pi * i) -- 比直接调用 math.pi 快
end

局部变量实践

1
2
3
4
5
6
7
8
9
10
11
-- 好的实践
local function calculate(a, b)
local result = a + b -- 函数内尽量使用局部变量
return result
end

-- 避免的做法
function calculate(a, b)
result = a + b -- 污染了全局空间
return result
end

3.6 变量命名最佳实践

命名风格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 局部变量:驼峰命名
local userName = "张三"
local maxCount = 100

-- 常量(约定):全大写加下划线
local MAX_SIZE = 1024
local DEFAULT_TIMEOUT = 30

-- 表/模块:首字母大写
local Person = {name = "", age = 0}
local MyModule = {}

-- 内部/私有:下划线开头
local _internalVar = "私有"
local function _helper()
-- 内部辅助函数
end

常见命名误区

1
2
3
4
5
6
7
8
-- 避免使用 Lua 保留字
-- local end = 10 -- 语法错误!

-- 避免覆盖内置函数
-- print = "overwrite" -- 这样做会覆盖 print 函数

-- 避免驼峰保留字风格
local nextValue = 1 -- 可以,但要小心 next 是内置函数

3.7 本章小结

  • 变量默认是全局的,使用 local 声明局部变量
  • 多值赋值可以一次给多个变量赋值,方便交换变量
  • 作用域按 do...end 块和函数体嵌套
  • 变量查找:当前块 → 外层块 → 文件级 → 全局
  • _G 是全局环境表,可以查看和操作所有全局变量
  • 局部变量性能更好,应优先使用

练习题

  1. 不使用 local 在函数内声明一个变量,在函数外访问它,验证其为全局变量
  2. 使用多值赋值交换三个变量的值:a=1, b=2, c=3 变成 a=3, b=1, c=2
  3. 编写一段代码展示作用域嵌套的变量屏蔽效果
  4. 通过 _G 表列出当前环境中所有以 “p” 开头的全局变量
  5. 将一个全局函数(如 tostring)缓存为局部变量并在循环中使用
ByteFisher
分享编程技术 · 记录钓鱼乐趣
扫码关注
▸ 扫码关注 ◂
Lua基础教程 系列
第 3/15 篇
分享: