变量与作用域 #
一、变量基础 #
1.1 变量声明 #
Lua 中变量不需要类型声明,直接赋值即可:
lua
-- 直接赋值
name = "Lua" -- 全局变量
local version = 5.4 -- 局部变量
-- 多变量赋值
local a, b, c = 1, 2, 3
-- 先声明后赋值
local x, y
x = 10
y = 20
1.2 变量命名 #
lua
-- 合法的变量名
local name = "张三"
local user_name = "合法"
local _private = "合法"
local userName = "合法"
-- 非法的变量名
-- local 2name = "非法" -- 不能以数字开头
-- local user-name = "非法" -- 不能包含连字符
-- local if = "非法" -- 不能使用关键字
1.3 变量默认值 #
lua
-- 未赋值的变量默认为 nil
local x
print(x) -- nil
-- 显式赋值为 nil 可以删除变量
local y = 10
y = nil
print(y) -- nil
二、局部变量 #
2.1 使用 local 声明 #
lua
-- 使用 local 声明局部变量
local count = 0
local name = "Lua"
local pi = 3.14159
-- 局部函数
local function greet()
print("Hello!")
end
2.2 作用域范围 #
lua
-- 代码块作用域
do
local x = 10
print(x) -- 10
end
-- print(x) -- 错误:x 不可见
-- 函数作用域
local function test()
local y = 20
print(y) -- 20
end
test()
-- print(y) -- 错误:y 不可见
-- 循环作用域
for i = 1, 3 do
local loop_var = i * 2
print(loop_var)
end
-- print(i) -- nil(for 的变量在循环外不可见)
-- print(loop_var) -- 错误
2.3 变量遮蔽 #
lua
local x = 1
do
local x = 2 -- 遮蔽外层的 x
print(x) -- 2
do
local x = 3 -- 遮蔽中间层的 x
print(x) -- 3
end
print(x) -- 2
end
print(x) -- 1
三、全局变量 #
3.1 默认全局 #
lua
-- 不使用 local 声明的变量是全局变量
name = "Lua"
function show()
print(name) -- 可以访问全局变量
end
show() -- Lua
3.2 全局变量表 _G #
lua
-- 所有全局变量都存储在 _G 表中
name = "Lua"
print(_G.name) -- Lua
-- 遍历所有全局变量
for k, v in pairs(_G) do
print(k, v)
end
-- 动态创建全局变量
local key = "dynamic_var"
_G[key] = "动态创建的值"
print(dynamic_var) -- 动态创建的值
3.3 检测全局变量 #
lua
-- 检查全局变量是否存在
if _G["myVar"] ~= nil then
print("myVar 存在")
end
-- 使用 rawget 避免 __index 元方法
if rawget(_G, "myVar") ~= nil then
print("myVar 存在")
end
3.4 全局变量的危险 #
lua
-- 意外创建全局变量
function calculate(a, b)
result = a + b -- 忘记 local!
return result
end
-- 检测全局变量泄漏
local function check_globals()
local known_globals = {}
for k in pairs(_G) do
known_globals[k] = true
end
return function()
for k in pairs(_G) do
if not known_globals[k] then
print("新全局变量:" .. k)
end
end
end
end
四、作用域规则 #
4.1 词法作用域 #
Lua 使用词法作用域(静态作用域):
lua
local x = 10
local function foo()
print(x) -- 访问外层的 x
end
local function bar()
local x = 20
foo() -- foo 仍然访问外层的 x = 10
end
bar() -- 10
4.2 闭包与作用域 #
lua
-- 闭包捕获外层变量
local function counter()
local count = 0
return function()
count = count + 1
return count
end
end
local c = counter()
print(c()) -- 1
print(c()) -- 2
print(c()) -- 3
-- 另一个计数器,独立的 count
local c2 = counter()
print(c2()) -- 1
4.3 作用域链 #
lua
local a = 1
local function outer()
local b = 2
local function inner()
local c = 3
print(a, b, c) -- 可以访问所有外层变量
end
inner()
-- print(c) -- 错误:c 不可见
end
outer()
-- print(b) -- 错误:b 不可见
五、最佳实践 #
5.1 优先使用局部变量 #
lua
-- 推荐:使用局部变量
local function process()
local result = 0
for i = 1, 100 do
result = result + i
end
return result
end
-- 不推荐:使用全局变量
function process()
result = 0 -- 全局变量
for i = 1, 100 do
result = result + i
end
return result
end
5.2 缓存全局访问 #
lua
-- 缓存常用全局函数
local print = print
local table = table
local string = string
-- 性能更好的循环
local concat = table.concat
local result = {}
for i = 1, 10000 do
result[i] = tostring(i)
end
print(concat(result, ","))
5.3 限制变量作用域 #
lua
-- 使用 do...end 限制作用域
local result
do
local temp1 = calculate_step1()
local temp2 = calculate_step2(temp1)
result = calculate_step3(temp2)
-- temp1, temp2 在这里自动释放
end
-- 只有 result 在后续可用
print(result)
5.4 避免全局污染 #
lua
-- 使用模块模式
local M = {}
M.version = "1.0"
function M.hello()
print("Hello!")
end
return M
-- 或使用严格模式检测
local function strict_mode()
local mt = {
__newindex = function(t, k, v)
error("禁止创建全局变量:" .. k, 2)
end,
__index = function(t, k)
error("访问未定义的全局变量:" .. k, 2)
end
}
setmetatable(_G, mt)
end
六、特殊变量 #
6.1 _G 全局表 #
lua
-- _G 是全局变量表
print(_G._G == _G) -- true
-- 遍历标准库
for name, value in pairs(_G) do
if type(value) == "table" then
print("库:" .. name)
end
end
6.2 _ENV 环境表(Lua 5.2+) #
lua
-- _ENV 是当前环境
local print = print -- 保存原始 print
-- 创建新环境
local env = {print = print, x = 10}
local code = [[print("x = " .. x)]]
-- 在新环境中执行
local func, err = load(code, "test", "t", env)
if func then
func()
end
-- 输出:x = 10
6.3 _VERSION 版本 #
lua
print(_VERSION) -- Lua 5.4
-- 版本检测
if _VERSION == "Lua 5.1" then
-- Lua 5.1 特定代码
elseif _VERSION == "Lua 5.4" then
-- Lua 5.4 特定代码
end
6.4 arg 命令行参数 #
lua
-- arg[0] 是脚本名
-- arg[1] 到 arg[n] 是参数
print("脚本:" .. arg[0])
for i = 1, #arg do
print("参数 " .. i .. ":" .. arg[i])
end
七、变量生命周期 #
7.1 局部变量生命周期 #
lua
-- 局部变量在作用域结束时销毁
local function create()
local t = {1, 2, 3}
return function()
return t -- 闭包延长了 t 的生命周期
end
end
local get_t = create()
print(#get_t()) -- 3
7.2 垃圾回收 #
lua
-- 手动触发垃圾回收
local t = {1, 2, 3}
t = nil -- 标记为可回收
collectgarbage() -- 立即回收
-- 查看内存使用
print(collectgarbage("count")) -- KB 为单位
八、实用模式 #
8.1 单例模式 #
lua
-- 使用局部变量实现单例
local singleton = nil
local function get_instance()
if not singleton then
singleton = {
value = 0,
increment = function(self)
self.value = self.value + 1
end
}
end
return singleton
end
8.2 私有变量 #
lua
-- 使用闭包实现私有变量
local function create_counter()
local count = 0 -- 私有变量
return {
increment = function()
count = count + 1
return count
end,
get = function()
return count
end,
reset = function()
count = 0
end
}
end
local counter = create_counter()
print(counter.increment()) -- 1
print(counter.increment()) -- 2
print(counter.get()) -- 2
counter.reset()
print(counter.get()) -- 0
8.3 配置模式 #
lua
-- 使用局部表存储配置
local config = {
host = "localhost",
port = 8080,
timeout = 30
}
-- 冻结配置(防止修改)
local function freeze(t)
local proxy = {}
local mt = {
__index = t,
__newindex = function()
error("配置不可修改", 2)
end
}
setmetatable(proxy, mt)
return proxy
end
config = freeze(config)
九、常见错误 #
9.1 忘记 local #
lua
-- 错误:忘记 local
function process()
result = 0 -- 全局变量!
for i = 1, 10 do
result = result + i
end
return result
end
-- 正确:使用 local
function process()
local result = 0
for i = 1, 10 do
result = result + i
end
return result
end
9.2 变量未定义 #
lua
-- 错误:使用未定义的变量
print(unknownVar) -- nil(不会报错,但可能是 bug)
-- 正确:检查变量
if unknownVar ~= nil then
print(unknownVar)
end
9.3 作用域混淆 #
lua
-- 错误:期望修改外层变量
local count = 0
local function increment()
local count = count + 1 -- 创建新的局部变量
end
increment()
print(count) -- 0
-- 正确:直接修改
local count = 0
local function increment()
count = count + 1 -- 修改外层变量
end
increment()
print(count) -- 1
十、总结 #
本章介绍了 Lua 的变量和作用域:
- 变量声明:使用
local声明局部变量 - 作用域规则:词法作用域,变量在代码块内有效
- 全局变量:存储在
_G表中,应尽量避免使用 - 闭包:函数可以捕获外层变量
- 最佳实践:优先使用局部变量,缓存全局访问
理解变量和作用域是编写高质量 Lua 代码的基础。下一章,我们将学习 Lua 的基本数据类型。
最后更新:2026-03-27