10.表
10.1 知识点
基本概念
- 表是 Lua 里最核心的复合数据结构。
- 数组、二维数组、字典、简单的类和结构体,都可以用表来组织。
- 表还提供了一些常用方法给我们使用。
- 表直接赋值只是复制引用,不会自动复制整张表。
a = { name = "韬哥" }
b = a
b.name = "韬老师"
print(a.name) -- 韬老师
print(b.name) -- 韬老师
上面这个例子里,a 和 b 指向的是同一张表。这个点后面写配置表、角色数据、临时数据时很容易踩坑。这里先知道有这个现象即可,深拷贝后面放到进阶篇单独整理。
一维数组
一维数组声明
- 一维数组声明语法:表变量 = { 元素1, 元素2, …, 元素n }
- 表的元素可以是任意类型。
a = { 1, 2, 3, "4", nil, "6", true, nil }
获得一维数组中的元素
- 获得一维数组中的元素语法:表变量[索引]
- Lua 中表的索引默认从 1 开始。
print(a[0]) -- nil
print(a[1]) -- 1
print(a[2]) -- 2
print(a[3]) -- 3
print(a[4]) -- 4
print(a[5]) -- nil
print(a[6]) -- "6"
print(a[7]) -- true
print(a[8]) -- nil
获取一维数组的长度
- 获取一维数组的长度语法:
#表变量 #是获取长度的关键字。- 如果数组中间有
nil,也就是出现了“空洞”,#返回的结果可能和直觉不一致。 - 所以数组内容不连续时,不要太依赖
#得到的长度。 - 实际项目里,连续数组用
#问题不大;如果是字典、稀疏表、有空洞的数组,就要谨慎。
a = { 1, 2, 3, "4", nil, "6", true, nil }
print(#a) -- 7(不同版本或不同构造方式下,空洞表的结果可能不稳定)
a = { 1, nil, 3, "4", nil }
print(#a) -- 1
a = { 1, 2, nil, 4, "5", true, nil }
print(#a) -- 2
遍历一维数组
-- 使用 for 循环遍历时,# 表变量获得表长的问题仍然存在
-- 连续数组可以这样写
-- 如果中间有 nil,就要注意遍历结果可能不完整
a = { 1, 2, 3, "4", nil, "6", true, nil }
for i = 1, #a do
print(a[i])
end
二维数组
二维数组声明
-- 二维数组声明语法:
-- 表变量 =
-- {
-- { 表1元素1, 表1元素2, 表1元素3 },
-- { 表2元素1, 表2元素2, 表2元素3 },
-- ...,
-- { 表n元素1, 表n元素2, 表n元素3 }
-- }
a = {
{ 1, 2, 3 },
{ 4, 5, 6 }
}
获得二维数组中的元素
-- 获得二维数组中的元素语法:表变量[索引1][索引2]
print(a[1][1]) -- 1
print(a[1][2]) -- 2
print(a[1][3]) -- 3
print(a[2][1]) -- 4
print(a[2][2]) -- 5
print(a[2][3]) -- 6
遍历二维数组
-- 使用两次 for 循环遍历
-- # 表变量获得表长的问题仍然存在,不赘述
for i = 1, #a do
b = a[i]
for j = 1, #b do
print(b[j])
end
end
自定义索引
- 表自定义索引声明语法:表变量 = { [索引1] = 元素1, [索引2] = 元素2, …, [索引n] = 元素n }
- 表自定义索引规则:指定索引的元素关联指定索引,未指定索引的元素会从 1 开始按顺序增加。
- 注意:
- 重复索引不会报错,同一个索引(key)后面的值会覆盖前面的值。
- 自定义索引会让表更像字典,不要再完全按连续数组去理解它。
- 同时
#表变量返回表长也可能不准确,不要盲信#表变量得到的表长。
a = { [0] = 1, 2, 3, [-1] = 4, 5 }
print(#a) -- 3,只把 2、3、5 算入表长
print(a[0]) -- 1
print(a[1]) -- 2
print(a[2]) -- 3
print(a[-1]) -- 4
print(a[3]) -- 5
-- 虽然 5 和 3 中间夹了个 -1 索引
-- 但是 5 还是被当成上一个没有自定义索引元素的下一个顺序索引
-- 比如上一个没有自定义索引的元素 3 是索引 2,所以 5 是索引 3
print(a[4]) -- nil,没有索引 4 的元素
a = { [1] = 1, [2] = 2, [4] = 4, [5] = 5 }
print(#a) -- 5,2 和 4 中间只隔了一个 nil,结果可能把 5 也算进去
for i = 1, #a do
print(a[i]) -- 1 2 nil 4 5
end
a = { [1] = 1, [2] = 2, [5] = 4, [6] = 6 }
print(#a) -- 2,2 和 5 中间隔了两个 nil,只把 1、2 算进去
for i = 1, #a do
print(a[i]) -- 1 2
end
迭代器遍历
#表变量得到的表长不一定准确,尤其是有空洞或者自定义索引时。- 连续数组可以用
for i = 1, #a do。 - 有空洞的数组、字典、自定义索引表,一般用迭代器遍历更稳。
next是pairs底层依赖的基础遍历函数。基础篇先会用pairs即可,不需要手写next。
ipairs遍历
ipairs可以遍历键值对,也可以只遍历键不遍历值。ipairs从索引 1 开始往后遍历,小于等于索引 0 的元素遍历不到。ipairs只适合连续数组,索引中间断了,后面的内容就遍历不到。- 比如如下遍历找不到 5 索引所在的元素 6,因为没有 4 元素。
- 可以看出,
ipairs仍然没有解决空洞数组的问题。
a = { [0] = 1, 2, [-1] = 3, 4, 5, [5] = 6 }
-- ipairs 迭代器遍历键值对
-- ipairs 遍历键值对语法:
-- for 键变量, 值变量 in ipairs(表变量) do
-- 循环体
-- end
for i, k in ipairs(a) do
print("ipairs遍历键值对" .. i .. "_" .. k)
-- ipairs遍历键值对1_2
-- ipairs遍历键值对2_4
-- ipairs遍历键值对3_5
end
-- ipairs 迭代器遍历键
-- ipairs 遍历键语法:
-- for 键变量 in ipairs(表变量) do
-- 循环体
-- end
for i in ipairs(a) do
print("ipairs遍历键" .. i)
-- ipairs遍历键1
-- ipairs遍历键2
-- ipairs遍历键3
end
pairs遍历
pairs可以遍历键值对,也可以只遍历键不遍历值。pairs能够把所有键都遍历出来,可以得到所有键值对。pairs能解决#表变量在自定义索引、字典、空洞表上的一些问题。- 但
pairs的遍历顺序不保证。不要写依赖pairs顺序的业务逻辑。
a = { [0] = 1, 2, [-1] = 3, 4, 5, [5] = 6 }
-- pairs 遍历键值对语法:
-- for 键变量, 值变量 in pairs(表变量) do
-- 循环体
-- end
-- pairs 能够把所有键都找到,这样就可以得到所有键值对
for i, v in pairs(a) do
print("pairs遍历键值对" .. i .. "_" .. v)
-- pairs遍历键值对1_2
-- pairs遍历键值对2_4
-- pairs遍历键值对3_5
-- pairs遍历键值对0_1
-- pairs遍历键值对-1_3
-- pairs遍历键值对5_6
end
-- pairs 遍历键语法:
-- for 键变量 in pairs(表变量) do
-- 循环体
-- end
for i in pairs(a) do
print("pairs遍历键" .. i)
-- pairs遍历键1
-- pairs遍历键2
-- pairs遍历键3
-- pairs遍历键0
-- pairs遍历键-1
-- pairs遍历键5
end
字典
字典的声明
-- 字典的声明语法:表变量 = { ["键1"] = "值1", ["键2"] = "值2", ..., ["键3"] = "值3" }
-- 字典是由键值对构成,和自定义索引声明类似,只是键和值多了双引号 "" 包裹
a = { ["name"] = "韬哥", ["age"] = 22, ["1"] = 1 }
访问字典值
-- 表变量["键"] 用中括号来访问值,键要带上双引号 ""
print(a["name"]) -- 韬哥
print(a["age"]) -- 22
print(a["1"]) -- 1
-- 表变量.键 用点访问值,类似 C# 中 .成员变量 的形式得到值
print(a.name) -- 韬哥
print(a.age) -- 22
-- 虽然可以通过 .成员变量 的形式得到值,但是不能是数字
-- print(a.1) -- 报错
print(a["1"]) -- 1
修改字典值
-- 表变量["键"] = "新值"
a["name"] = "韬老师"
print(a["name"]) -- 韬老师
-- 表变量.键 = "新值"
a.name = "韬老师帅"
print(a.name) -- 韬老师帅
新增字典值
-- 表变量["新键"] = "新值"
a["sex"] = false
print(a["sex"]) -- false
-- 表变量.新键 = "新值"
a.handsome = true
print(a.handsome) -- true
删除字典值
-- 表变量["键"] = nil
a["sex"] = nil
print(a["sex"]) -- nil
-- 表变量.键 = nil
a.handsome = nil
print(a.handsome) -- nil
字典的遍历
-- 遍历字典一般用 pairs 迭代器
-- 键值对遍历
for k, v in pairs(a) do
-- 可以传多个参数,一样可以打印出来
print(k, v)
-- 1 1
-- name 韬老师帅
-- age 22
end
-- 遍历键,通过键得到值
for k in pairs(a) do
print(k)
print(a[k])
-- 1
-- 1
-- name
-- 韬老师帅
-- age
-- 22
end
-- 遍历值,可以用 _ 省略键
for _, v in pairs(a) do
print(_, v)
-- 1 1
-- name 韬老师帅
-- age 22
end
类和结构体
- Lua 中默认没有 C# 那种面向对象语法,需要自己用表来模拟。
- Lua 中实现简单的类和结构体,底层思路都离不开表。
类声明
-- 类声明语法:
-- 类 = {
-- 成员变量,
-- 成员函数,
-- ...
-- }
Student = {
-- 年龄
age = 1,
-- 性别
sex = true,
-- 打印函数1
Print1 = function()
print("进入打印函数1")
print(age)
-- 这样打印的 age 和 Student 类中的 age 没有任何关系
-- 打印的 age 是一个全局变量
-- 在表内部函数中,调用类本身的属性或者方法,要指定类
-- 类.属性 或 类.方法()
print(Student.age)
print(Student.sex)
print("退出打印函数1")
end,
-- 打印函数2
Print2 = function(myStudent)
print("进入打印函数2")
-- 可以使用有参函数,把当前类作为一个参数传进来
-- 在函数内部通过参数访问当前类
print(Student.age)
print(myStudent.sex)
print("退出打印函数2")
end
}
实例化类对象
- C# 是使用类
new出对象,通过对象访问成员。 - Lua 中默认没有
new的概念,表更像是一个装着很多字段和函数的容器。 - 真正完整的面向对象写法后面在面向对象篇再整理。
得到类的成员变量
-- 直接 类.变量 得到变量
print(Student.age) -- 1
print(Student.sex) -- true
在类外添加的成员变量
-- 声明类过后,可以直接在类外 类.变量 = 值 添加成员变量
Student.name = "韬老狮"
print(Student.name) -- 韬老狮
使用.调用类的成员方法
Student.Print1()
-- 进入打印函数1
-- nil
-- 1
-- true
-- 退出打印函数1
Student.Print2(Student) -- 传入当前类作为参数
-- 进入打印函数2
-- 1
-- true
-- 退出打印函数2
使用.在类外添加的成员方法
-- 声明类过后,可以直接在类外
-- 类.方法 = function()
-- 函数体
-- end
-- 来添加成员方法
Student.Print3 = function()
print("进入打印函数3")
print(Student.age)
print(Student.sex)
print("退出打印函数3")
end
Student.Print3()
-- 进入打印函数3
-- 1
-- true
-- 退出打印函数3
使用:调用类的成员方法
-- 冒号调用方法,会默认把调用者作为调用方法的第一个参数传入方法中
Student:Print2() -- 虽然没有显式传入 Student,但因为是 : 调用函数,已经隐式传入 Student
-- 进入打印函数2
-- 1
-- true
-- 退出打印函数2
使用:在类外添加的成员方法 self来表示默认传入的第一个参数
-- 声明类过后,可以直接在类外
-- 类:方法 = function()
-- 函数体
-- end
-- 来添加成员方法
-- 使用了 : 声明方法后,代表方法会有一个默认参数
-- 在方法内,通过 self 表示默认传入的第一个参数
function Student:Print4() -- 虽然没有显式参数,但是因为是 : 声明函数,已经隐式让这个函数有参数了
print("进入打印函数4")
print(self.age)
print(self.sex)
print("退出打印函数4")
end
在类外调用使用:在类外添加的成员方法
-- Student.Print4() -- 报错,Print4 因为是 : 声明函数,需要传入参数
Student.Print4(Student) -- 传入了 Student 类自身作为参数,正常调用
-- 进入打印函数4
-- 1
-- true
-- 退出打印函数4
Student:Print4() -- 冒号调用方法,会把调用者 Student 作为第一个参数传进去,正常调用
-- 进入打印函数4
-- 1
-- true
-- 退出打印函数4
表的公共方法
插入 table.insert
t1 = { { age = 1, name = "111" }, { age = 2, name = "222" } }
t2 = { name = "韬老狮", sex = true }
-- table.insert(要插入元素的表, 插入的元素)
-- 这里会把 t2 作为 t1 顺序索引的最后一个元素
print(#t1) -- 2
table.insert(t1, t2)
print(#t1) -- 3
print(t1[1].name) -- 111
print(t1[2].name) -- 222
print(t1[3].name) -- 韬老狮,代表把 t2 插入成功了
删除 table.remove
t1 = { { age = 1, name = "111" }, { age = 2, name = "222" }, { name = "韬老狮", sex = true } }
-- table.remove(要移除元素的表) 会移除传入表最后一个索引的内容
print(#t1) -- 3
table.remove(t1)
print(#t1) -- 2
print(t1[1].name) -- 111
print(t1[2].name) -- 222
print(t1[3]) -- nil,最后一个元素被移除了
-- table.remove(要移除元素的表, 移除元素索引)
print(#t1) -- 2
table.remove(t1, 1)
print(#t1) -- 1
print(t1[1].name) -- 222,name 为 111 的元素被移除了
排序 table.sort
t1 = { 5, 2, 4, 3, 1 }
-- table.sort(要排序的表) 默认升序排列
table.sort(t1)
for _, v in pairs(t1) do
print(v)
-- 1
-- 2
-- 3
-- 4
-- 5
end
-- table.sort(要排序的表, 排序规则函数)
-- 排序函数接受两个参数,通常命名为 a 和 b,用于表示待比较的两个元素。
-- 排序函数根据 a 和 b 的比较结果返回 true 或 false,用来决定元素的相对顺序。
-- 如果排序函数返回 true,表示 a 应该排在 b 前面。
-- 如果排序函数返回 false,表示 b 应该排在 a 前面。
-- 排序函数必须返回布尔值,且只有 true 或 false。
-- 降序
table.sort(t1, function(a, b)
return a > b
end)
for _, v in pairs(t1) do
print(v)
-- 5
-- 4
-- 3
-- 2
-- 1
end
-- 升序
function AscendingSort(a, b)
return a < b
end
table.sort(t1, AscendingSort)
for _, v in pairs(t1) do
print(v)
-- 1
-- 2
-- 3
-- 4
-- 5
end
拼接 table.concat
t1 = { "123", "456", "789", "10101" }
-- table.concat(要拼接的表, "元素间的符号") 返回值是一个拼接好的字符串
str = table.concat(t1, "@@")
print(str) -- 123@@456@@789@@10101
10.2 知识点代码
Lesson10_表.lua
print("**********表************")
print("**********知识点一 基本概念************")
-- 表是 Lua 里最核心的复合数据结构
-- 数组、二维数组、字典、简单的类和结构体,都可以用表来组织
-- 表还提供了一些常用方法给我们使用
-- 表直接赋值只是复制引用,不会自动复制整张表
a = { name = "韬哥" }
b = a
b.name = "韬老师"
print(a.name) -- 韬老师
print(b.name) -- 韬老师
print("**********知识点二 一维数组************")
-- 一维数组声明语法:表变量 = { 元素1, 元素2, ..., 元素n }
-- 表的元素可以是任意类型
a = { 1, 2, 3, "4", nil, "6", true, nil }
-- 获得一维数组中的元素语法:表变量[索引]
-- Lua 中表的索引默认从 1 开始
print(a[0]) -- nil
print(a[1]) -- 1
print(a[2]) -- 2
print(a[3]) -- 3
print(a[4]) -- 4
print(a[5]) -- nil
print(a[6]) -- "6"
print(a[7]) -- true
print(a[8]) -- nil
-- 获取一维数组的长度语法:#表变量
-- # 是获取长度的关键字
-- 如果数组中间有 nil,也就是出现了“空洞”,# 返回的结果可能和直觉不一致
-- 所以数组内容不连续时,不要太依赖 # 得到的长度
-- 实际项目里,连续数组用 # 问题不大
-- 如果是字典、稀疏表、有空洞的数组,就要谨慎
a = { 1, 2, 3, "4", nil, "6", true, nil }
print(#a) -- 7(不同版本或不同构造方式下,空洞表的结果可能不稳定)
a = { 1, nil, 3, "4", nil }
print(#a) -- 1
a = { 1, 2, nil, 4, "5", true, nil }
print(#a) -- 2
-- 遍历一维数组
-- 使用 for 循环遍历时,# 表变量获得表长的问题仍然存在
-- 连续数组可以这样写
-- 如果中间有 nil,就要注意遍历结果可能不完整
a = { 1, 2, 3, "4", nil, "6", true, nil }
for i = 1, #a do
print(a[i])
end
print("**********知识点三 二维数组************")
-- 二维数组声明语法:
-- 表变量 =
-- {
-- { 表1元素1, 表1元素2, 表1元素3 },
-- { 表2元素1, 表2元素2, 表2元素3 },
-- ...,
-- { 表n元素1, 表n元素2, 表n元素3 }
-- }
a = {
{ 1, 2, 3 },
{ 4, 5, 6 }
}
-- 获得二维数组中的元素语法:表变量[索引1][索引2]
print(a[1][1]) -- 1
print(a[1][2]) -- 2
print(a[1][3]) -- 3
print(a[2][1]) -- 4
print(a[2][2]) -- 5
print(a[2][3]) -- 6
-- 遍历二维数组
-- 使用两次 for 循环遍历
-- # 表变量获得表长的问题仍然存在,不赘述
for i = 1, #a do
b = a[i]
for j = 1, #b do
print(b[j])
end
end
print("**********知识点四 自定义索引************")
-- 表自定义索引声明语法:表变量 = { [索引1] = 元素1, [索引2] = 元素2, ..., [索引n] = 元素n }
-- 表自定义索引规则:指定索引的元素关联指定索引,未指定索引的元素会从 1 开始按顺序增加
-- 注意:
-- 重复索引不会报错,同一个索引(key)后面的值会覆盖前面的值
-- 自定义索引会让表更像字典,不要再完全按连续数组去理解它
-- 同时 #表变量 返回表长也可能不准确,不要盲信 #表变量 得到的表长
a = { [0] = 1, 2, 3, [-1] = 4, 5 }
print(#a) -- 3,只把 2、3、5 算入表长
print(a[0]) -- 1
print(a[1]) -- 2
print(a[2]) -- 3
print(a[-1]) -- 4
print(a[3]) -- 5
-- 虽然 5 和 3 中间夹了个 -1 索引
-- 但是 5 还是被当成上一个没有自定义索引元素的下一个顺序索引
-- 比如上一个没有自定义索引的元素 3 是索引 2,所以 5 是索引 3
print(a[4]) -- nil,没有索引 4 的元素
a = { [1] = 1, [2] = 2, [4] = 4, [5] = 5 }
print(#a) -- 5,2 和 4 中间只隔了一个 nil,结果可能把 5 也算进去
for i = 1, #a do
print(a[i]) -- 1 2 nil 4 5
end
a = { [1] = 1, [2] = 2, [5] = 4, [6] = 6 }
print(#a) -- 2,2 和 5 中间隔了两个 nil,只把 1、2 算进去
for i = 1, #a do
print(a[i]) -- 1 2
end
print("**********知识点五 迭代器遍历************")
-- #表变量 得到的表长不一定准确,尤其是有空洞或者自定义索引时
-- 连续数组可以用 for i = 1, #a do
-- 有空洞的数组、字典、自定义索引表,一般用迭代器遍历更稳
-- next 是 pairs 底层依赖的基础遍历函数
-- 基础篇先会用 pairs 即可,不需要手写 next
-- ipairs 遍历
-- ipairs 可以遍历键值对,也可以只遍历键不遍历值
-- ipairs 从索引 1 开始往后遍历,小于等于索引 0 的元素遍历不到
-- ipairs 只适合连续数组,索引中间断了,后面的内容就遍历不到
-- 比如如下遍历找不到 5 索引所在的元素 6,因为没有 4 元素
-- 可以看出,ipairs 仍然没有解决空洞数组的问题
a = { [0] = 1, 2, [-1] = 3, 4, 5, [5] = 6 }
-- ipairs 迭代器遍历键值对
-- ipairs 遍历键值对语法:
-- for 键变量, 值变量 in ipairs(表变量) do
-- 循环体
-- end
for i, k in ipairs(a) do
print("ipairs遍历键值对" .. i .. "_" .. k)
-- ipairs遍历键值对1_2
-- ipairs遍历键值对2_4
-- ipairs遍历键值对3_5
end
-- ipairs 迭代器遍历键
-- ipairs 遍历键语法:
-- for 键变量 in ipairs(表变量) do
-- 循环体
-- end
for i in ipairs(a) do
print("ipairs遍历键" .. i)
-- ipairs遍历键1
-- ipairs遍历键2
-- ipairs遍历键3
end
-- pairs 遍历
-- pairs 可以遍历键值对,也可以只遍历键不遍历值
-- pairs 能够把所有键都遍历出来,可以得到所有键值对
-- pairs 能解决 #表变量 在自定义索引、字典、空洞表上的一些问题
-- 但 pairs 的遍历顺序不保证。不要写依赖 pairs 顺序的业务逻辑
a = { [0] = 1, 2, [-1] = 3, 4, 5, [5] = 6 }
-- pairs 遍历键值对语法:
-- for 键变量, 值变量 in pairs(表变量) do
-- 循环体
-- end
-- pairs 能够把所有键都找到,这样就可以得到所有键值对
for i, v in pairs(a) do
print("pairs遍历键值对" .. i .. "_" .. v)
-- pairs遍历键值对1_2
-- pairs遍历键值对2_4
-- pairs遍历键值对3_5
-- pairs遍历键值对0_1
-- pairs遍历键值对-1_3
-- pairs遍历键值对5_6
end
-- pairs 遍历键语法:
-- for 键变量 in pairs(表变量) do
-- 循环体
-- end
for i in pairs(a) do
print("pairs遍历键" .. i)
-- pairs遍历键1
-- pairs遍历键2
-- pairs遍历键3
-- pairs遍历键0
-- pairs遍历键-1
-- pairs遍历键5
end
print("**********知识点六 字典************")
-- 字典的声明
-- 字典的声明语法:表变量 = { ["键1"] = "值1", ["键2"] = "值2", ..., ["键3"] = "值3" }
-- 字典是由键值对构成,和自定义索引声明类似,只是键和值多了双引号 "" 包裹
a = { ["name"] = "韬哥", ["age"] = 22, ["1"] = 1 }
-- 访问字典值
-- 表变量["键"] 用中括号来访问值,键要带上双引号 ""
print(a["name"]) -- 韬哥
print(a["age"]) -- 22
print(a["1"]) -- 1
-- 表变量.键 用点访问值,类似 C# 中 .成员变量 的形式得到值
print(a.name) -- 韬哥
print(a.age) -- 22
-- 虽然可以通过 .成员变量 的形式得到值,但是不能是数字
-- print(a.1) -- 报错
print(a["1"]) -- 1
-- 修改字典值
-- 表变量["键"] = "新值"
a["name"] = "韬老师"
print(a["name"]) -- 韬老师
-- 表变量.键 = "新值"
a.name = "韬老师帅"
print(a.name) -- 韬老师帅
-- 新增字典值
-- 表变量["新键"] = "新值"
a["sex"] = false
print(a["sex"]) -- false
-- 表变量.新键 = "新值"
a.handsome = true
print(a.handsome) -- true
-- 删除字典值
-- 表变量["键"] = nil
a["sex"] = nil
print(a["sex"]) -- nil
-- 表变量.键 = nil
a.handsome = nil
print(a.handsome) -- nil
-- 字典的遍历
-- 遍历字典一般用 pairs 迭代器
-- 键值对遍历
for k, v in pairs(a) do
-- 可以传多个参数,一样可以打印出来
print(k, v)
-- 1 1
-- name 韬老师帅
-- age 22
end
-- 遍历键,通过键得到值
for k in pairs(a) do
print(k)
print(a[k])
-- 1
-- 1
-- name
-- 韬老师帅
-- age
-- 22
end
-- 遍历值,可以用 _ 省略键
for _, v in pairs(a) do
print(_, v)
-- 1 1
-- name 韬老师帅
-- age 22
end
print("**********知识点七 类和结构体************")
-- Lua 中默认没有 C# 那种面向对象语法,需要自己用表来模拟
-- Lua 中实现简单的类和结构体,底层思路都离不开表
-- 类声明语法:
-- 类 = {
-- 成员变量,
-- 成员函数,
-- ...
-- }
Student = {
-- 年龄
age = 1,
-- 性别
sex = true,
-- 打印函数1
Print1 = function()
print("进入打印函数1")
print(age)
-- 这样打印的 age 和 Student 类中的 age 没有任何关系
-- 打印的 age 是一个全局变量
-- 在表内部函数中,调用类本身的属性或者方法,要指定类
-- 类.属性 或 类.方法()
print(Student.age)
print(Student.sex)
print("退出打印函数1")
end,
-- 打印函数2
Print2 = function(myStudent)
print("进入打印函数2")
-- 可以使用有参函数,把当前类作为一个参数传进来
-- 在函数内部通过参数访问当前类
print(Student.age)
print(myStudent.sex)
print("退出打印函数2")
end
}
-- C# 是使用类 new 出对象,通过对象访问成员
-- Lua 中默认没有 new 的概念,表更像是一个装着很多字段和函数的容器
-- 真正完整的面向对象写法后面在面向对象篇再整理
-- 得到类的成员变量
-- 直接 类.变量 得到变量
print(Student.age) -- 1
print(Student.sex) -- true
-- 在类外添加的成员变量
-- 声明类过后,可以直接在类外 类.变量 = 值 添加成员变量
Student.name = "韬老狮"
print(Student.name) -- 韬老狮
-- 使用 . 调用类的成员方法
Student.Print1()
-- 进入打印函数1
-- nil
-- 1
-- true
-- 退出打印函数1
Student.Print2(Student) -- 传入当前类作为参数
-- 进入打印函数2
-- 1
-- true
-- 退出打印函数2
-- 使用 . 在类外添加的成员方法
-- 声明类过后,可以直接在类外
-- 类.方法 = function()
-- 函数体
-- end
-- 来添加成员方法
Student.Print3 = function()
print("进入打印函数3")
print(Student.age)
print(Student.sex)
print("退出打印函数3")
end
Student.Print3()
-- 进入打印函数3
-- 1
-- true
-- 退出打印函数3
-- 使用 : 调用类的成员方法
-- 冒号调用方法,会默认把调用者作为调用方法的第一个参数传入方法中
Student:Print2() -- 虽然没有显式传入 Student,但因为是 : 调用函数,已经隐式传入 Student
-- 进入打印函数2
-- 1
-- true
-- 退出打印函数2
-- 使用 : 在类外添加的成员方法
-- 声明类过后,可以直接在类外
-- 类:方法 = function()
-- 函数体
-- end
-- 来添加成员方法
-- 使用了 : 声明方法后,代表方法会有一个默认参数
-- 在方法内,通过 self 表示默认传入的第一个参数
function Student:Print4() -- 虽然没有显式参数,但是因为是 : 声明函数,已经隐式让这个函数有参数了
print("进入打印函数4")
print(self.age)
print(self.sex)
print("退出打印函数4")
end
-- Student.Print4() -- 报错,Print4 因为是 : 声明函数,需要传入参数
Student.Print4(Student) -- 传入了 Student 类自身作为参数,正常调用
-- 进入打印函数4
-- 1
-- true
-- 退出打印函数4
Student:Print4() -- 冒号调用方法,会把调用者 Student 作为第一个参数传进去,正常调用
-- 进入打印函数4
-- 1
-- true
-- 退出打印函数4
print("**********知识点八 表的公共方法************")
-- 插入
t1 = { { age = 1, name = "111" }, { age = 2, name = "222" } }
t2 = { name = "韬老狮", sex = true }
-- table.insert(要插入元素的表, 插入的元素)
-- 这里会把 t2 作为 t1 顺序索引的最后一个元素
print(#t1) -- 2
table.insert(t1, t2)
print(#t1) -- 3
print(t1[1].name) -- 111
print(t1[2].name) -- 222
print(t1[3].name) -- 韬老狮,代表把 t2 插入成功了
-- 删除
t1 = { { age = 1, name = "111" }, { age = 2, name = "222" }, { name = "韬老狮", sex = true } }
-- table.remove(要移除元素的表) 会移除传入表最后一个索引的内容
print(#t1) -- 3
table.remove(t1)
print(#t1) -- 2
print(t1[1].name) -- 111
print(t1[2].name) -- 222
print(t1[3]) -- nil,最后一个元素被移除了
-- table.remove(要移除元素的表, 移除元素索引)
print(#t1) -- 2
table.remove(t1, 1)
print(#t1) -- 1
print(t1[1].name) -- 222,name 为 111 的元素被移除了
-- 排序
t1 = { 5, 2, 4, 3, 1 }
-- table.sort(要排序的表) 默认升序排列
table.sort(t1)
for _, v in pairs(t1) do
print(v)
-- 1
-- 2
-- 3
-- 4
-- 5
end
-- table.sort(要排序的表, 排序规则函数)
-- 排序函数接受两个参数,通常命名为 a 和 b,用于表示待比较的两个元素
-- 排序函数根据 a 和 b 的比较结果返回 true 或 false,用来决定元素的相对顺序
-- 如果排序函数返回 true,表示 a 应该排在 b 前面
-- 如果排序函数返回 false,表示 b 应该排在 a 前面
-- 排序函数必须返回布尔值,且只有 true 或 false
-- 降序
table.sort(t1, function(a, b)
return a > b
end)
for _, v in pairs(t1) do
print(v)
-- 5
-- 4
-- 3
-- 2
-- 1
end
-- 升序
function AscendingSort(a, b)
return a < b
end
table.sort(t1, AscendingSort)
for _, v in pairs(t1) do
print(v)
-- 1
-- 2
-- 3
-- 4
-- 5
end
-- 拼接
t1 = { "123", "456", "789", "10101" }
-- table.concat(要拼接的表, "元素间的符号") 返回值是一个拼接好的字符串
str = table.concat(t1, "@@")
print(str) -- 123@@456@@789@@10101
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com