Lua 数组(快速上手)

什么是 Lua 数组?初学者的入门指南

在学习 Lua 编程语言的过程中,你一定会遇到一个高频概念:Lua 数组。虽然 Lua 本身没有“数组”这种独立的数据类型,但它的表(table)结构可以完美模拟数组的行为,因此我们通常把使用整数键(从 1 开始)的表称为“Lua 数组”。

你可以把 Lua 数组想象成一个带编号的抽屉盒子。每个抽屉都有一个唯一的编号(索引),你可以往里面放数据,也可以根据编号取出内容。这种结构非常灵活,也特别适合处理一系列相关的数据。

Lua 数组的核心优势在于它的灵活性和轻量级设计。相比其他语言中固定长度的数组,Lua 的“数组”可以动态增长,不需要预先声明大小。这种特性让它在游戏开发、配置管理、脚本处理等场景中表现出色。

创建数组与初始化

在 Lua 中,创建一个数组其实很简单,只需要使用花括号 {} 来定义一个表,并填入元素即可。注意:Lua 的索引从 1 开始,而不是 0,这和许多其他语言有所不同。

-- 创建一个包含 5 个数字的 Lua 数组
local scores = { 85, 92, 78, 96, 88 }

-- 打印整个数组
print("成绩数组:", table.concat(scores, ", "))

注释:
第 1 行定义了一个局部变量 scores,并用花括号初始化了 5 个数字。
第 4 行使用 table.concat 函数将数组元素用逗号连接起来输出,便于查看。
输出结果为:成绩数组: 85, 92, 78, 96, 88

你也可以在初始化时显式指定索引,虽然这不是必须的。但当你想从非 1 开始索引时,这种写法就很有用。

-- 显式指定索引的数组(不推荐用于标准 Lua 数组)
local days = {
  [1] = "周一",
  [2] = "周二",
  [3] = "周三"
}

print("星期数组:", table.concat(days, "、"))

注释:
这里使用 [1] = "周一" 的方式显式定义键值对。
虽然语法正确,但普通数组通常不需要这样写,直接写值即可。
输出结果为:星期数组: 周一、周二、周三

访问与修改数组元素

访问 Lua 数组中的元素和访问普通数组一样,使用方括号 [] 加索引。记住:索引从 1 开始,这一点非常重要,否则容易出错。

local fruits = { "苹果", "香蕉", "橙子", "葡萄" }

-- 访问第一个元素
print("第一个水果:", fruits[1])  -- 输出:第一个水果: 苹果

-- 访问最后一个元素
print("最后一个水果:", fruits[4])  -- 输出:最后一个水果: 葡萄

-- 修改第二个元素
fruits[2] = "芒果"
print("修改后的数组:", table.concat(fruits, "、"))  -- 输出:修改后的数组: 苹果、芒果、橙子、葡萄

注释:
fruits[1] 访问第一个元素,fruits[4] 访问第四个元素。
fruits[2] = "芒果" 将原香蕉替换为芒果。
table.concat 用于格式化输出,避免手动拼接字符串。

如果你尝试访问一个不存在的索引,比如 fruits[10],Lua 会返回 nil,表示“没有值”。这在调试时是一个重要的线索。

遍历 Lua 数组

遍历数组是编程中最常见的操作之一。Lua 提供了多种方式来遍历数组,最常用的是 for 循环配合 ipairs 函数。

local colors = { "红色", "绿色", "蓝色", "黄色" }

-- 使用 ipairs 遍历数组(推荐方式)
for index, value in ipairs(colors) do
  print("索引:", index, "值:", value)
end

注释:
ipairs 是专门用于遍历数组的迭代器,它会从索引 1 开始,按顺序遍历到第一个 nil 值为止。
index 是当前元素的索引,value 是当前元素的值。
输出结果为:

索引: 1 值: 红色
索引: 2 值: 绿色
索引: 3 值: 蓝色
索引: 4 值: 黄色

如果你用普通的 pairs,它会遍历所有键值对,包括非整数键,所以不推荐用于纯数组场景。

-- 不推荐用于数组遍历
for k, v in pairs(colors) do
  print("键:", k, "值:", v)
end

注释:
虽然 pairs 也能遍历数组,但它会遍历所有键,包括未来可能添加的非整数键。
且顺序不确定,不利于数组处理。因此,优先使用 ipairs

常用数组操作函数

Lua 为数组提供了几个实用的内置函数,它们都来自 table 模块。掌握这些函数,能让你在处理数据时事半功倍。

添加元素

使用 table.insert 可以在数组末尾或指定位置插入元素。

local animals = { "猫", "狗", "鸟" }

-- 在末尾添加元素
table.insert(animals, "兔子")
print("添加兔子后:", table.concat(animals, "、"))  -- 输出:添加兔子后: 猫、狗、鸟、兔子

-- 在第 2 个位置插入元素
table.insert(animals, 2, "兔子")
print("在第2位插入后:", table.concat(animals, "、"))  -- 输出:在第2位插入后: 猫、兔子、狗、鸟、兔子

注释:
table.insert(animals, "兔子") 在末尾插入。
table.insert(animals, 2, "兔子") 在索引 2 处插入,原位置元素后移。
该函数会自动调整后续索引。

删除元素

使用 table.remove 可以删除指定索引的元素。

local cities = { "北京", "上海", "广州", "深圳" }

-- 删除最后一个元素
table.remove(cities)
print("删除最后一个后:", table.concat(cities, "、"))  -- 输出:删除最后一个后: 北京、上海、广州

-- 删除第 2 个元素
table.remove(cities, 2)
print("删除第2个后:", table.concat(cities, "、"))  -- 输出:删除第2个后: 北京、广州

注释:
table.remove(cities) 默认删除最后一个元素。
table.remove(cities, 2) 删除索引为 2 的元素。
删除后,后续元素的索引会自动前移。

获取数组长度

使用 # 操作符可以获取数组长度。

local numbers = { 1, 2, 3, 4, 5 }

print("数组长度:", #numbers)  -- 输出:数组长度: 5

注释:
#numbers 返回数组的长度,即最后一个连续整数索引的值。
注意:如果中间有 nil# 可能返回不准确值。
例如:{1, 2, nil, 4}# 会返回 2,而不是 4。
所以,仅当数组是连续的整数索引时# 才可靠。

操作 语法 说明
添加元素 table.insert(t, value) 在末尾插入
添加元素(指定位置) table.insert(t, pos, value) 在指定位置插入
删除元素 table.remove(t) 删除最后一个
删除元素(指定位置) table.remove(t, pos) 删除指定位置
获取长度 #t 返回连续整数索引的长度

实际应用案例:学生成绩管理系统

下面我们来做一个小项目:用 Lua 数组管理一组学生的成绩。

-- 学生姓名数组
local students = { "小明", "小红", "小刚", "小丽" }

-- 对应成绩数组
local scores = { 88, 92, 76, 95 }

-- 打印所有学生和成绩
print("学生与成绩列表:")
for i = 1, #students do
  print(string.format("学生 %s: 成绩 %d 分", students[i], scores[i]))
end

-- 计算平均分
local sum = 0
for i = 1, #scores do
  sum = sum + scores[i]
end
local average = sum / #scores
print(string.format("平均成绩: %.2f 分", average))  -- 输出:平均成绩: 87.75 分

注释:
使用 string.format 格式化输出,让结果更清晰。
#students#scores 保证了两个数组长度一致。
这种结构非常适合处理成对的数据。

小结

Lua 数组虽然没有独立类型,但通过表(table)的整数键机制,实现了高效、灵活的数据管理。它特别适合处理顺序数据,如列表、队列、配置项等。

关键点回顾:

  • Lua 数组索引从 1 开始
  • 使用花括号 {} 初始化
  • ipairs 遍历,# 获取长度
  • table.inserttable.remove 增删元素
  • 保持索引连续,避免 nil 中断

无论你是初学者还是中级开发者,掌握 Lua 数组的这些基本操作,都能让你在编写脚本、处理数据时更加得心应手。它简洁、高效,正是 Lua 语言魅力的体现。