我们继续来学一些东西

多维数组

数组这东西咱们之前其实已经学过了,基本上没什么说的了,因为lua里面数组字典都是一个东西

但是有一个东西不得不提那就是table的数组的一面的多维数组性

说人话就是和其他语言一样,lua的数组也可以嵌套,而且用法一模一样

二维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
local matrix = {
{ 1, 2, 3 },
{ 4, 5, 6 },
{ 7, 8, 9 }
}

print(matrix[1][1]) -- 1
print(matrix[2][3]) -- 6
print(matrix[3][2]) -- 8

for i = 1, #matrix do
for j = 1, #matrix[i] do
io.write(matrix[i][j], " ")
end
print()
end

image-20260310180344743

三维数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
local cube = {
{
{ 1, 2 },
{ 3, 4 }
},
{
{ 5, 6 },
{ 7, 8 }
}
}

for i = 1, #cube do
print("layer", i)

for j = 1, #cube[i] do
for k = 1, #cube[i][j] do
io.write(cube[i][j][k], " ")
end
print()
end

print()
end

image-20260310180446020

递归遍历数组

因为手动敲代码非常麻烦,而且每增加一层数组就要套上一个for循环,所以我们采用递归遍历,实现一劳永逸

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
--t        当前遍历的 table
--callback 处理数据的函数
--path 记录当前坐标(路径)
local function walkArray(t, callback, path)

--如果没有 path 就创建一个空表
path = path or {}

--pairs用于遍历表
--k 表示当前元素的索引(key),从1开始
--v 表示当前元素的值(value)
for k, v in pairs(t) do
--例如:
--最开始 path = {}
--#path = 0
--所以 path[#path+1] = path[1] = k

--如果当前k=1
--那么 path 就变成 {1}
path[#path + 1] = k

--这里可以这样理解:
--假设我们把 cube 当成一个洋葱
--我们一层一层往里面拨

--第一层
--cube里面的元素其实是两个table

--第二层
--里面的元素还是table

--第三层
--才是最终的数字

--所以程序每次都会检查
--当前元素是不是table

if type(v) == "table" then

--如果还是table
--说明还没有拨到最里面
--于是继续把这个table塞进walkArray函数
--继续往里面遍历

--注意:
--这里的path不是新的table
--而是同一个path在不断增加路径
walkArray(v, callback, path)

else

--如果不是table
--说明已经到达最底层元素
--此时就执行callback函数

--callback会收到两个参数
--value = 当前值
--path = 当前值的路径
callback(v, path)

end

--这一行非常关键
--path[#path] = nil 的作用是删除最后一个路径

--例如:
--path = {1,2,3}
--删除后变成
--path = {1,2}

--这样程序就可以回到上一层继续遍历
--否则path会越来越长
path[#path] = nil
end
end


--三维数组
local cube = {

--第一层
{
--第二层
{
--第三层
1,
2,
3
},
{
--第三层
4,
5,
6
}
},

{
--第二层
{
--第三层
7,
8,
9
},
{
--第三层
10,
11,
12
}
}
}


--调用函数
walkArray(cube,

--匿名函数(也叫回调函数)
--当walkArray找到一个最终的值时
--就会执行这个函数

function(value, path)

--打印 index
io.write("index ")

--path里面存的是当前元素的完整路径
--例如 {1,2,3}
--表示 cube[1][2][3]

for i = 1, #path do
io.write("[" .. path[i] .. "]")
end

--打印值
print(" = " .. value)

end
)

image-20260310185303265

你别说,我真的看不懂这写的什么意思,我以前从来没有认真看过递归(因为用不上我也从来不看这个),现在理解起来还是有点困难的

迭代器

迭代器包括泛型 for 迭代器,无状态的迭代器,多状态的迭代器

其中泛型 for 迭代器我们已经学过了,我们就不说了,这个就是我们前面说的遍历表的ipairs和pairs这些东西

泛型 for 迭代器

语法为

1
2
3
for var_1, var_2 in iterator_func, state, init do
-- 循环体
end
泛型 for 部分 作用 具体值
iterator_func 每次迭代被调用的函数(返回下一个值) square
state 迭代器固定数据(不会变的东西) 3 (最大迭代次数)
init 迭代器固定数据(不会变的东西) 0 (控制变量初始值)
var_1, var_2 循环体变量,用来接收迭代器返回值 i, n(循环体变量)

例如

1
2
3
4
5
6
7
8
9
array = {"Google", "Runoob"}

for key,value in ipairs(array)
do
print(key, value)
end
--Google
--Runoob
-
函数 类型 功能
ipairs(t) 无状态 按索引顺序遍历数组部分
pairs(t) 多状态 遍历表中所有键值对
string.gmatch(s, pattern) 多状态 按模式匹配字符串
io.lines(filename) 多状态 按行读取文件

无状态的迭代器(stateless iterator)

无状态:迭代函数本身不保存任何内部状态,它只依赖两个输入:

  1. 状态常量(通常是固定的数据集合,比如表)
  2. 控制变量(循环中表示当前位置的索引或计数器)

循环机制:每一次迭代,Lua 都调用迭代函数 f(state, control),由迭代函数返回下一个元素

优势:不需要闭包开销,效率高,适合简单、固定的序列遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
-- 无状态迭代器
local function iter(n, i)
i = i + 1
if i <= n then
return i
end
end

local n = 5
for i in iter, n, 0 do
print(i)
end
--1
--2
--3
--4
--5

解析:
iter 是迭代器函数,每次被调用时接收两个参数:
n(state)
i(上一次返回的值,初始是 0

返回下一个值,直到返回 nil 时循环结束

特点:迭代器本身不记状态,状态由循环外部传递进来
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function square(iteratorMaxCount, currentNumber)
if currentNumber < iteratorMaxCount then
currentNumber = currentNumber + 1
return currentNumber, currentNumber * currentNumber
end
end

for i, n in square, 3, 0 do
print(i, n)
end
--1 1
--2 4
--3 9

解析:

迭代函数:square(iteratorMaxCount, currentNumber)
每次被调用,传入状态常量 iteratorMaxCount(最大迭代次数)和控制变量 currentNumber(上一次返回的值)

返回值:返回下一个索引和它的平方

Lua 的 for 循环会不断调用 square,直到返回 nil 停止

多状态的迭代器(stateful iterator)

多状态:迭代器需要维护多个状态,可能包括:

  • 当前索引
  • 集合长度
  • 缓存数据

实现方式

  1. 闭包:迭代函数内保存状态变量。
  2. 表封装状态:状态信息放在 table 中,迭代函数每次读取。

特点:迭代器自己记住状态,循环不必每次传入控制变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
local function next_pair(t)
local key = nil
return function()
key = next(t, key)
if key then
return key, t[key]
end
end
end

local t = {a=1, b=2, c=3}
for k, v in next_pair(t) do
print(k, v)
end
--a 1
--b 2
--c 3

解析:

next_pair(t) 返回一个闭包函数,这个闭包保存了内部状态(key)。

每次调用闭包,都会从表中取下一个键值对。

循环结束条件是闭包返回 nil

特点:迭代器自己保存状态,外部循环无需传递状态。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
local array = {"Google", "Runoob"}

function elementIterator(collection)
local index = 0
local count = #collection
-- 闭包函数,保存状态
return function()
index = index + 1
if index <= count then
return collection[index]
end
end
end

for element in elementIterator(array) do
print(element)
end
--Google
--Runoob