我们继续来学一些东西

多维数组

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

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

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

二维数组

LUA已复制
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

三维数组

LUA已复制
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循环,所以我们采用递归遍历,实现一劳永逸

LUA已复制
--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 迭代器

语法为

LUA已复制
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(循环体变量)

例如

LUA已复制
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),由迭代函数返回下一个元素

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

LUA已复制
-- 无状态迭代器
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 时循环结束

特点:迭代器本身不记状态,状态由循环外部传递进来
LUA已复制
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 中,迭代函数每次读取。

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

LUA已复制
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。

特点:迭代器自己保存状态,外部循环无需传递状态。
LUA已复制
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