Unity:lua热更新(二)——Lua语法(续)
写在前面:
写本系列(自用)的目的是回顾已经学过的知识、记录新学习的知识或是记录心得理解,方便自己以后快速复习,减少遗忘。主要是C#代码部分。
二、Lua语法
5、条件分支语句
(1)单分支
单分支的语法是:if 条件 then...end
print("************条件分支语句************")
a = 9if a > 5 thenprint("123")
end
![]()
(2)双分支
加上else即可
if a < 5 thenprint("123")
elseprint("321")
end
![]()
(3)多分支
使用elseif即可,和C#区别不大。
if分支的条件也可以用逻辑运算符连接
if a < 5 thenprint("123")
elseif a == 6 thenprint("6")
elseif a == 7 thenprint("7")
elseprint("other") --这句没有也行
endif a >= 3 and a <= 9 thenprint("3到9之间")
end
![]()
最后,需要注意的是lua中没有switch语法,要自己实现。
6、循环语句
(1)while语句
语法是while 条件 do...end
print("************循环语句************")
print("************while语句************")
num = 0while num < 5 doprint(num)num = num + 1
end

(2)do while语句
语法是repeat....until 条件,类似于C#的do while语句,第一次一定会执行。
print("************do while语句************")
num = 0
repeatprint(num)num = num + 1
until num > 5 --满足条件跳出 结束条件

(3)for语句
for循环与C#区别较大。使用for i = 1, 5 do,指的是i从1到5,i会自动+1。
print("************for语句************")
for i = 1, 5 do --i会默认+1print(i)
end

如果不想只加一,可以使用for i = 1, 5, 2 do,第三个数为增量。当然,增量可以为负
for i = 1, 5, 2 do print(i)
endfor i = 5, 1, -1 do print(i)
end

7、函数
函数的语法是
function 函数名()
end
或者
a = function()
end
(1)无参无返回
需要注意的是,在函数声明之前,不能调用。因为lua是从上到下顺序执行的。
有两种声明函数的方式,第一种:
print("************函数************")
print("************无参无返回************")function F1()print("F1函数")
endF1()
第二种,有点类似C#的委托
F2 = function()print("F2函数")
endF2()

(2)有参
在函数的括号内加上传入的参数即可function F3(a)
需要注意的是参数可以传任意类型,参数可以和函数参数个数不匹配,不会报错只会补空nil或者丢弃。
print("************有参************")function F3(a)print(a)
end
F3(1)
F3("123")
F3(true)
F3()
F3(1, 2, 3)

(3)有返回
直接return即可,如下。调用函数后可以声明变量来接收返回的值
print("************有返回************")
function F4(a)return a
endtemp = F4(1)
print(temp)
![]()
如果是多返回值时,在前面声明多个变量来接取即可。
--如果变量不够 不影响 值接取对应位置的返回值
--如果变量多了 不影响 直接赋值nil
function F5(a)return a, "123", true
endtemp, temp2, temp3 = F5(1)
print(temp)
print(temp2)
print(temp3)

(4)函数的类型与重载
使用type可以获取函数的类型:
print("************函数的类型************")
print(type(F5))
![]()
函数重载指的是:函数名相同 参数类型不同或者参数个数不同
但lua不支持重载,默认调用最后一个声明的函数
print("************函数的重载************")function F6()print("南瓜牛乳小丸子好吃")
endfunction F6(str)print(str )
endF6()
F6("红烧排骨")

(5)变长参数
变长参数在参数列表里打三个点即可:function F7(...)。变长参数的使用:需要用一个表存起来 再用:
print("************变长参数************")function F7(...)arg = {...}for i =1, #arg doprint(arg[i])end
endF7(1,2,"12",true,5,6)

(6)函数嵌套与闭包
函数嵌套就是在一个函数中再声明一个函数,并且将这个函数返回出来,如下:
print("************函数嵌套************")
function F8()F9 = function()print(123);endreturn F9
endf9 = F8()
f9()--也可以直接写为
function F9()return function()print(123);end
end
![]()
闭包发生在函数嵌套中,会改变传入参数的生命周期。例如下例,F10传入的参数为x,F10中 存在函数嵌套,嵌套函数中使用了参数x,那么,这个x就会被保存下来,假设传入的x为10。我们声明f10来存储F10返回的函数,那么,此时的f10相当于:
function(y)
return 10 + y
end
x是局部变量,本应不存在了,但因为闭包,它的生命周期被改变了。
这样,调用f10(5)时,输出的就是15。
--闭包
function F10(x)--改变了传入参数的生命周期return function(y)return x + yend
endf10 = F10(10)
print(f10(5))
![]()
8、复杂数据类型 table
所有的复杂类型本质上都是table(表)。
(1)数组
数组中可以转任意类型的元素,但是需要注意的是,在 Lua 中,数组中间包含 nil 会导致不可预测的行为,应该尽量避免。
例如,某些版本的lua,遍历时,如果数组中间出现nil,编辑器就会认为此时数组结束了,后面的值就会丢失,获取长度时也同理,只能得到nil前的长度。
但某些版本的lua,能正常将nil看作一个数组元素。因此还是不要随意在数组中包含nil。
lua 中 索引从1开始,获取长度依然使用#
print("************复杂数据类型 table************")print("************数组************")a = {1, 2, 3, 4, "5", 6, "7", nil, true}
b = {1, nil, 3, 4, "5", 6, "7", nil, true}print(a[0])
print(a[1])
print(a[5])
print(a[8])
print(a[9])print(#a)
print(#b)

(2)数组的遍历
使用for循环即可。
print("************数组的遍历************")
for i = 1, #a doprint(a[i])
end

(3)二维数组及其遍历
严格来说,lua不存在二维数组,但是可以模拟实现。如下,数组a中的元素均为数组。
遍历方式分别遍历两层即可。
print("************二维数组************")
a = {{1,2,3},{4,5,6}}
print(a[1][1])
print(a[2][1])print("************二维数组的遍历************")
for i = 1,#a dob = a[i]for j=1,#b doprint(b[j])end
end

(4)自定义索引
可以在数组中自定义索引,例如aa = {[0] = 1, 2, 3, [-1]=4, 5}
自定义索引0和索引-1,可以直接通过aa[0]访问。但是,如果输出aa的长度,长度依然是3,因为0和-1它都不认识,只会从1开始累计长度。
print("************自定义索引************")
aa = {[0] = 1, 2, 3, [-1]=4, 5}
print(aa[0])
print(aa[-1])
print(#aa) -- 0和-1它都不认识

此外,如果自定义索引导致原索引断开,也会出现一系列问题。例如,这里索引值只存在1,2,4,但输出aa的长度时,它会认为此时长度为4,这显然是不对的。
在遍历时,aa[3]会自动赋值为nil
aa = {[1] = 1, [2] = 2, [4] = 4}
print(#aa)
for i = 1,#aa doprint(aa[i])
end

因此自定义索引其实不常用。
9、迭代器遍历
主要是用来遍历表的,#得到长度并不准确,所以一般不用#遍历,而是使用迭代器。
(1)ipairs迭代器遍历
ipairs还是从1开始往后遍历,小于等于0的值得不到,只能找到连续索引,如果中间断续了,也无法找到后面的内容。所以不是很常用。
print("************迭代器遍历************")
a ={[0] = 1, 2, [-1] = 3, 4, 5, [5] = 6}print("************ipairs迭代器遍历************")
for i, k in ipairs(a) doprint("ipairs遍历" .. i .. "_" ..k)
end

(2)pairs迭代器遍历
它能够把所有的键都找到
print("************pairs迭代器遍历************")
for i, v in pairs(a) doprint("pairs遍历".. i .. "_" ..v)
endprint("************pairs迭代器遍历键************")
for i in pairs(a) doprint("pairs遍历键".. i)
end

10、字典
(1)字典的声明
字典是由键值对构成的,a = {["name"] = "Alice", ["age"] = 18, ["1"] = 5}
如果想访问字典元素,有两种方式,a["name"]或者a.name
print("************字典************")
print("************字典的声明************")a = {["name"] = "Alice", ["age"] = 18, ["1"] = 5}
print(a["name"])
print(a["age"])print(a.name)
print(a.age)

修改和新增也很简单,直接a["name"] ="爱丽丝",a["sex"] = false即可
--修改
a["name"] ="爱丽丝"
print(a["name"])--新增
a["sex"] = false
print(a["sex"])
![]()
其实不存在严格意义上的删除,把字典元素置空为nil:
--删除
a["sex"] = nil
print(a["sex"])
(2)字典的遍历
不能用ipairs 一定要用pairs,否则会报错。需要注意的是,可以遍历键值对,遍历键,但是不存在单独遍历值。
print("************字典的遍历************")
for k,v in pairs(a) do--可以传多个参数 一样可以打印出来print(k, v)--print(k, v, 3, 4)
end--只遍历键
for k in pairs(a) doprint(k)print(a[k])
end--本质上也是通过遍历键得到值
for _,v in pairs(a) doprint(v)
end

11、类和结构体
(1)声明
lua中是默认没有面向对象的 需要我们自己来实现 成员变量 成员函数。如下声明了一个类,有成员变量年龄和性别,成员函数Up和Learn。
除此之外,还可以在表外声明变量:
Student.name = "Alice"
Student.Speak = function()print("说话")
end--也可以这样声明
function Student.Speak2()print("说话2")
end
与C#不同的是,在Up函数中,我们想要打印成员变量age。但是直接使用print(age),这样写这个age和表中的age没有任何关系。想要在表内部函数中调用表本身属性或者方法一定要指定是谁的属性和方法。所以要使用名字.属性或者名字.方法print(Student.age)。
第二种能在函数内部调用自己的属性或者方法的方法,如Learn中所示,把自己作为参数传进来,在内部进行访问。
print("************类和结构体************")Student = {--年龄age = 1, --性别sex = true,Up = function()--print(age) print(Student.age)print("我成长了")end,Learn = function(t)print(t.sex)print("好好学习,天天向上")end
}Student.Learn(Student)

(2)点和冒号
lua中点和冒号的区别是,点就是正常调用,冒号调用方法会默认把调用者作为第一个参数传入方法。
Student:Learn()

加入冒号后,可以有新的声明方式:此时声明了Speak3函数,该函数有一个参数,默认是自己。
lua中,有一个关键字 self表示 默认传入的第一个参数
function Student:Speak3()print(self.name .. "说话")
end
print(Student.age)
Student.Up()
Student.Speak()
Student.Speak2()
Student:Speak3()

12、表的公共操作
table提供了一些公共方法
(1)插入
使用table.insert(),例如table.insert(t1, t2) 表示在t1中插入t2
print("************表的公共操作************")t1 = {{age = 1, name = "123"}, {age =2, name = "345"}}t2 = {name = "Alice", sex = true}print("************插入************")
--插入
print(#t1)
table.insert(t1, t2) --在t1中插入t2
print(#t1)
print(t1[1])
print(t1[2])
print(t1[3])
print(t1[3].sex)

(2)删除
删除指定元素
remove方法 传表进去 会移除最后一个索引的内容
print("************删除************")table.remove(t1)
print(#t1)
print(t1[1].name)

remove方法 传两个参数 第一个参数是要移除内容的表
第二个参数是要移除内容的索引
table.remove(t1,1)
print(t1[1].name)
![]()
(4)排序
直接使用table.sort(),括号内传入需要排序的表即可。默认为升序
print("************排序************")
print("************升序************")
t2 = {5, 2, 7, 9, 5}
table.sort(t2)
for _,v in pairs(t2) doprint(v)
end

如果想要为降序,可以在第二个参数处传入一个函数,类似于C#委托。
print("************降序************")
table.sort(t2, function(a, b)if a > b thenreturn trueend
end)
for _,v in pairs(t2) doprint(v)
end

(5)拼接
连接函数,用于拼接表中元素,返回值是一个字符串。一般只有数字和字符串拼,很多类型拼接都会报错,所以用的少。
print("************拼接************")
tb = {"123", "456", "789", "10101"}
str = table.concat( tb, ";")
print(str)

