12、复杂数据类型 table
所有的复杂数据类型都是table(表)
1.数组
在lua中 索引不从0开始而是从1开始
#是通用的获取长度的关键字
在打印长度的时候 lua会忽略掉nil
如果表中某一位变成nil,会影响#获取的长度 (若中间有nil后面长度都被忽略)
例:
a = {1,2,3,4,"123",true,nil}
print(#a) = 6
a = {1,2,nil,4,"123",true,nil}
print(#a) = 2
2.数组的遍历
例:
for i = 1,#a do
print(a[i])
end
3.二维数组
例:
a = {{1,2,3},{4,5,6}}
4.二维数组的遍历
for i = 1,#a do
b = a[i]
for j = 1,#b do
print(b[j])
end
end
5.自定义索引
例:
aa = {[1] = 1,[2] = 2,[4] = 4,[6] = 6}
print(#aa)
for i = 1,#aa do
print(aa[i])
end
13、迭代器遍历
迭代器遍历 主要是用来遍历表的
#得到长度 其实并不准确 一般不要用#来遍历表
a = {[0] = 1,2,[-1] = 3, 4, 5,[5] = 6}
1.ipairs迭代器遍历
ipairs
ipairs遍历 还是 从1开始往后遍历的 小于等于0的值得不到
只能找到连续索引的 键 如果中间断序了 他也无法遍历出后面的内容
例:
for i,k in ipairs(a) do
print("ipairs遍历键值"..i.."_"..k)
end
2.ipairs迭代器遍历键
例:
for i in ipairs(a) do
print("ipairs遍历键值"..i)
end
3.pairs迭代器遍历
pairs可以把所有的键都找到 通过键可以得到对应的值(推荐用)
例:
for i,v in pairs(a) do
print("pairs遍历键值"..i.."_"..v)
end
4.pairs迭代器遍历键
例:
for i in pairs(a) do
print("pairs遍历键值"..i)
end
14、字典
1.字典的声明
a = {["name"] = "XX",["age"] = 18,["sex"]=true}
访问单个变量
print(a["name"])
print(a.name)
修改直接覆盖对应键的值即可
新增直接加就可以 例如:a["12345"] = true
删除将键值赋为nil即可
2.字典的遍历
例:
for k,v in pairs(a) do
--可以传多个参数 一样可以打印出来
print(k,v)
end
for k in pairs(a) do
print(k)
print(a[k])
end
for _,v in pairs(a) do
print(_,v)
end
3.类和结构体
Lua中是默认没有面向对象的 需要我们自己来实现
例:
Student = {
--年龄
age = 1,
--性别
sex = true,
--成长函数
Up = function()
--这样写 这个age 和表中的age没有任何关系 它是一个全局变量
--print(age)
--想要在表内部函数中 调用表本身的属性或者方法
--一定要指定是谁的 所以要使用 表名.属性 或 表名.方法
print(Student.age)
print("我成长了")
end,
--学习函数
Learn = function(t)
--第二种 能够在函数内部调用自己属性或者方法的 方法
--把自己作为一个参数传进来 在内部 访问
print(t.sex)
print("好好学习,天天向上")
end
}
Lua中 .和冒号的区别
Student.Learn(Student)
冒号调用方法 会默认把调用者 作为第一个参数传入方法中
Student:Learn()
申明表过后 在表外去申明表有的变量和方法
Student.name = "XXX"
Student.Speak = function()
print("说话")
end
函数的第三种申明方式
function Student:Speak2()
--lua中 有一个关键字 self 表示 默认传入的第一个参数
print(self.name.."说话2")
end
C#要是使用类 实例化对象new 静态直接点
Lua中类的表现 更像是一个类中有很多 静态变量和函数
print(Student.age)
print(Student.name)
Student.Up()
Student.Speak()
Student:Speak2()
Student.Speak2(Student)
4.表的公共操作
t1 = {{age = 1,name = "123"},{age = 2,name = "345"}}
t2 = {name = "XXX",sex = true}
插入
table.insert(t1,t2);
移除
table.remove(t1)
--remove方法 传两个参数 第一个参数 是要移除内容的表
--第二个参数 是要移除内容的索引
table.remove(t1,1)
排序
t2 = {5,2,7,9,5}
--传入要排序的表 默认 降序排列
table.sort(t2)
降序
--传入两个参数 第一个是用于排序的表
--第二个是 排序规则函数
例:
table.sort(t2,function(a,b)
if a>b then
return true
end
end)
拼接
tb = {"123","456","789","10101"}
str = table.concat(tb,",")
15、多脚本执行
1.全局变量和本地变量
全局变量
即为正常声明的变量
本地变量(局部变量)
需要在变量名字前面加一个 local
2.多脚本执行
关键字 require("脚本名")
3.脚本卸载
如果是require加载执行的脚本 加载一次过后不会再被执行
关键字 package.loaded["脚本名"]
卸载已经执行过的脚本
package.loaded["脚本名"] = nil
require 执行一个脚本时 可以在脚本最后返回一个外部希望获取的内容
local testLA = require("脚本名") (可以在要执行的脚本末端写一个return 变量名,可以让testLA接收到)
4.大G表
_G表是一个总表(table) 他将我们申明的所有全局的变量都存储在其中
本地变量 加了local的变量是不会存到大_G表中
遍历大G表
for k,v in pairs(_G) do
print(k,v)
end
16、特殊用法
1.多变量赋值
local a,b,c = 1,2,"123"
多变量赋值 如果后面的值不够 会自动补空 如果后面的值多了 会自动省略
2.多返回值
同上原理
多返回值时 用几个变量接 就有几个值
如果少了 就少接几个 如果多了 就自动补空
3.and or
--逻辑与 逻辑或
-- and or 他们不仅可以连接 boolean 任何东西都可以用来连接
-- 在lua中 只有 nil 和 false 才认为是假
-- "短路"——对于and来说 有假则假 对于or来说 有真则真
-- 所以 他们只需要判断 第一个 是否满足 就会停止计算了
4.三目运算符
由于lua不支持三目运算符 所以我们可以利用and or的机制来实现
x = 3
y = 2
-- ? :
local res = (x>y) and x or y
17、协同程序
1.协程的创建
--常用方式
--coroutine.create()
fun = function()
print(123)
end
co = coroutine.create(fun)
--协程的本质是一个线程对象
这里返回的类型是一个线程thread
用coroutine.wrap() 返回的类型是函数
2.协程的运行
coroutine.resume(co)
3.协程的挂起
coroutine.yield(i)
4.协程的状态
coroutine.status(协程对象)
5.协程运行状态
coroutine.running()
6.提供示例
fun2 = function()
local i = 1
while true do
print(i)
i = i + 1
--协程的挂起函数
print(coroutine.status(co3))
print(coroutine.running())
coroutine.yield(i)
end
end
co3 = coroutine.create(fun2)
--默认第一个返回值 是 协程是否启动成功
--yield里面的返回值
isOk,tempI = coroutine.resume(co3)
print(isOk,tempI)
isOk,tempI = coroutine.resume(co3)
print(isOk,tempI)
isOk,tempI = coroutine.resume(co3)
print(isOk,tempI)
co4 = coroutine.wrap(fun2)
--这种方式的协程调用 也可以有返回值 只是没有默认第一个返回值了
print("返回值"..co4())
print("返回值"..co4())
print("返回值"..co4())
--coroutine.status(协程对象)
--dead 结束
--suspended 暂停
--running 进行中
print(coroutine.status(co3))
print(coroutine.status(co))
--这个函数可以得到当前正在 运行的协程的线程号
print(coroutine.running())
18、元表
1.元表概念
--任何表变量都可以作为另一个表变量的元表
--任何表变量都可以有自己的元表(爸爸)
--当我们子表中进行一些特定操作时
--会执行元表中的内容
2.设置元表
meta = {}
myTable = {}
--设置元表函数
--第一个参数 子表
--第二个参数 (爸爸)
setmetatable(myTable,meta)
3.特定操作
(1)__tostring
meta2 = {
--当子表要被当作字符串使用时 会默认调用这个元表中的tostring方法
__tostring = function(t)
return t.name
end
}
myTable2 = {
name = "XXX2"
}
--设置元表函数
--第一个参数 子表
--第二个参数 (爸爸)
setmetatable(myTable2,meta2)
print(myTable2)
(2)__call
meta3 = {
--当子表要被当作字符串使用时 会默认调用这个元表中的tostring方法
__tostring = function(t)
return t.name
end,
--当子表被当做一个函数来使用时 会默认调用这个__call中的内容
--当希望传参数时 一定要记住 默认第一个参数 是调用者自己
__call = function(a,b)
print(a)
print(b)
print("XXX真吊")
end
}
myTable3 = {
name = "XXX3"
}
--设置元表函数
--第一个参数 子表
--第二个参数 (爸爸)
setmetatable(myTable3,meta3)
--把子表当作函数使用 就会调用元表的 __call方法
myTable3(1)
(3)运算符重载
meta4 = {
--相当于运算符重载 当子表使用+运算符时 会调用该方法
--运算符+
__add = function(t1,t2)
return t1.age + t2.age
end,
--运算符-
__sub = function(t1,t2)
return t1.age - t2.age
end,
--运算符*
__mul = function(t1,t2)
return 1
end,
--运算符/
__div = function(t1,t2)
return 2
end,
--运算符%
__mod = function(t1,t2)
return 3
end,
--运算符^
__pow = function(t1,t2)
return 4
end,
--运算符==
__eq = function(t1,t2)
return true
end,
--运算符<
__lt = function(t1,t2)
return true
end,
--运算符<=
__le = function(t1,t2)
return false
end,
--运算符..
__concat = function(t1,t2)
return "567"
end
}
myTable4 = {age = 1}
setmetatable(myTable4,meta4)
myTable5 = {age = 2}
setmetatable(myTable5,meta4)
print(myTable4 + myTable5)
print(myTable4 - myTable5)
print(myTable4 * myTable5)
print(myTable4 / myTable5)
print(myTable4 % myTable5)
print(myTable4 ^ myTable5)
--如果要用条件运算符 来比较两个对象
--这两个对象的元表一定要一致 才能准确调用方法
print(myTable4 == myTable5)
print(myTable4 < myTable5)
print(myTable4 <= myTable5)
print(myTable4..myTable5)
4.__index和__newIndex
meta6Father = {
age = 1
}
meta6Father.__index = meta6Father
meta6 = {
--age = 1
}
--__index的赋值 写在表外面来初始化
meta6.__index = meta6
--meta6.__index = {age = 2}
myTable6 = {}
setmetatable(meta6,meta6Father)
setmetatable(myTable6,meta6)
--得到元表的方法
print(getmetatable(myTable6))
--__index 当子表中 找不到某一个属性时
--会到元表中 __index指定的表去找属性
print(myTable6.age)
--rawget 当我们使用它时 会去找自己身上有没有这个变量
myTable6.age = 1
print(rawget(myTable6,"age"))
--newIndex 当赋值时,如果赋值一个不存在的索引
--那么会把这个值赋值到newindex所指的表中 不会修改自己
meta7 = {}
meta7.__newindex = {}
myTable7 = {}
setmetatable(myTable7,meta7)
myTable7.age = 1
print(myTable7.age)
print(meta7.__newindex.age)
--rawset 该方法会忽略newindex的设置 只会该自己的变量
rawset(myTable7,"age",2)
print(myTable7.age)