0Pricing
Lua Academy · 课时

在 Lua 中声明变量

了解全局变量与局部变量的区别,以及命名约定

在 Lua 中声明变量 是 CoddyKit 上的免费 Lua Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Lua Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Lua Academy 课程共包含 4 节课。

全局变量与局部变量

在 Lua 中,变量默认是全局变量。不使用 local 关键字而写下 x = 10,会创建一个可以从任何地方访问的全局变量。使用 local x = 10 则会将变量限制在当前代码块及其嵌套代码块中。

为了性能和安全性,请始终优先使用 local。访问局部变量比访问全局变量更快,因为全局变量需要在 _G 表中进行哈希查找。

x = 100          -- global variable
local y = 200    -- local variable

do
  local z = 300  -- block-local
  print(x, y, z) -- 100  200  300
end

print(x, y)      -- 100  200
print(z)         -- nil  (out of scope)

local 关键字

local 关键字会声明一个作用域限定在最近外层代码块中的变量。代码块可以是函数体、do...end 代码块、循环体或文件代码块。局部变量会在声明它的那一行创建,并在其代码块结束时不再存在。

您可以在一行中声明多个局部变量,并同时为它们赋初值。未初始化的局部变量默认值为 nil。

local a, b, c = 1, 2, 3
print(a, b, c)    -- 1  2  3

local d, e = 10   -- e is nil
print(d, e)       -- 10  nil

local f           -- nil until assigned
f = 42
print(f)          -- 42

变量命名约定

Lua 标识符遵循以下规则:必须以字母或下划线开头,后面可以跟字母、数字或下划线。Lua 区分大小写,因此 Value、value 和 VALUE 是三个不同的变量。

按照 convention:普通变量使用 camelCase 或 snake_case,常量使用 UPPER_CASE,私有模块字段以下划线作为前缀。除循环计数器外,请避免使用单字母名称。

local myVariable = 1     -- camelCase
local my_variable = 2    -- snake_case
local MAX_SIZE = 100     -- constant convention
local _private = "hidden" -- private convention

-- Case sensitivity demo
local lua = "lower"
local Lua = "upper"
print(lua, Lua)  -- lower  upper

_G 全局表

Lua 中的所有全局变量都存放在一个名为 _G 的特殊表中。写下 x = 10 等价于 _G.x = 10。您可以通过遍历 _G 查看所有全局变量,这对调试很方便,但用于生产代码时存在风险。

在 Lua 5.2+ 中,_ENV 是实际的环境表,而 _G 初始化时会指向它。理解这一点后,您就可以通过替换 _ENV 来为代码创建沙箱。

myGlobal = 42
print(_G.myGlobal)   -- 42

-- Setting via _G is the same as direct assignment
_G.another = "hello"
print(another)        -- hello

-- Counting globals (many built-ins exist)
local count = 0
for k in pairs(_G) do count = count + 1 end
print("Globals:", count)

多重赋值

Lua 支持多重赋值:您可以在一条语句中为多个变量赋值。右侧表达式会先求值,然后从左到右进行赋值。如果变量多于值,多出的变量会得到 nil;如果值多于变量,多出的值会被丢弃。

因此,无需临时变量即可轻松交换变量。

-- Swap without temp variable
local a, b = 10, 20
a, b = b, a
print(a, b)   -- 20  10

-- More variables than values
local x, y, z = 1, 2
print(x, y, z)  -- 1  2  nil

-- More values than variables
local p, q = 1, 2, 3  -- 3 is discarded
print(p, q)   -- 1  2

作用域与代码块边界

Lua 的代码块分隔形式包括:do...end、函数体、if/elseif/else...end、while...end、repeat...until 和 for...end。每种形式都会创建一个新的作用域层级。do...end 代码块可以只用于限制作用域,而不包含其他逻辑。

在 for 循环头中声明的局部变量,其作用域限于循环体,不会泄漏到外部。

for i = 1, 3 do
  local msg = "item " .. i
  print(msg)
end
-- print(i)   -- would be nil, i is gone
-- print(msg) -- would be nil, msg is gone

-- do...end for manual scoping
do
  local temp = expensive_computation or 0
  print(temp)
end
-- temp is nil here

常量:local convention

Lua 没有内置的 const 关键字。通常使用 UPPER_CASE 名称和 local 来表示某个值不应发生变化。将常量作为局部变量放在模块顶部,还可以向即时编译器提示这些值是稳定的。

如果需要真正的不可变性,可以使用带有 __newindex 的代理表,在修改时触发错误——我们将在元表课程中介绍这一点。

local MAX_RETRIES = 3
local PI = 3.14159265358979
local APP_VERSION = "1.0.0"

-- Use them as read-only by convention
local area = PI * 5 * 5
print(area)           -- 78.539...
print(MAX_RETRIES)    -- 3

变量遮蔽

当内层作用域声明了一个与外层变量同名的局部变量时,就会发生遮蔽。内层声明会创建一个全新的变量,在其作用域内隐藏外层变量。外层变量不会改变,并会在内层作用域结束后重新可见。

变量遮蔽可能令人困惑;请尽量在嵌套作用域中使用不同的名称,但有时遮蔽是有意为之的,例如在嵌套循环中重复使用循环变量名称。

local x = "outer"
do
  local x = "inner"  -- shadows outer x
  print(x)            -- inner
end
print(x)              -- outer (unchanged)

local n = 10
for n = 1, 3 do       -- loop n shadows outer n
  print(n)            -- 1, 2, 3
end
print(n)              -- 10 (outer unchanged)

避免污染全局环境

意外创建全局变量是 Lua 中常见的错误:误写局部变量名称会悄悄创建一个新的全局变量。strict.lua 模块(项目中通常会引入)通过向 _G 添加元表,捕获对未声明全局变量的读取和写入。

更简单的方法是始终使用 local,并运行 luac -p 或使用 luacheck 等代码检查工具,在运行前检测意外的全局变量。

-- Dangerous: typo creates a global silently
local counter = 0
coutner = 5  -- typo! creates global 'coutner'
print(counter)  -- 0 (not 5!)
print(coutner)  -- 5 (the typo global)

-- Fix: always use local keyword
local score = 0
score = 10  -- assigns to existing local
print(score) -- 10

将 nil 赋值会删除全局变量

将全局变量设置为 nil 会从 _G 中移除它,并释放内存。这是“删除”全局变量的正确方式。对于局部变量,只需让它们超出作用域即可达到相同效果——垃圾回收器会回收相应内存。

在多重赋值中传入 nil 时请务必小心:在某些上下文中,尤其是右侧包含函数调用时,它可能会截断参数列表。

myGlobal = "exists"
print(myGlobal)   -- exists
print(_G.myGlobal ~= nil)  -- true

myGlobal = nil
print(myGlobal)   -- nil
print(_G.myGlobal ~= nil)  -- false
-- The entry is removed from _G

快速检查

在 for 循环体内使用 local x = 5 声明的变量,其作用域是什么?

回顾:在 Lua 中声明变量

本课的要点:

  • 变量默认是全局变量——请始终使用 local
  • 局部变量更快(无需哈希查找),也更安全
  • 多重赋值:a, b = b, a 可在一行中完成交换
  • 所有全局变量都存放在 _G 中;将其设置为 nil 会删除它们
  • 遮蔽:内层的 local 会隐藏外层变量,但不会改变它
  • 按照 convention,使用 UPPER_CASE 表示常量

下一步:算术、关系和逻辑运算符。

常见问题解答

「在 Lua 中声明变量」课时是免费的吗?

是的 — 「在 Lua 中声明变量」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Lua Academy 课程的其余内容,请升级到 CoddyKit PRO。 Lua Academy 课程共包含 4 节课。

「在 Lua 中声明变量」这节课中我会学到什么?

了解全局变量与局部变量的区别,以及命名约定 你通过在浏览器中直接运行的动手代码来练习 Lua Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Lua Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Lua Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「在 Lua 中声明变量」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Lua Academy 课中编写并运行代码吗?

能。每节 Lua Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. Lua 数据类型概览
  2. 在 Lua 中声明变量
  3. 算术运算符和关系运算符
  4. 类型强制转换和显式转换
← 返回 Lua Academy