Lua环境搭建
1、下载 lua for window
https://github.com/rjpcomputing/luaforwindows
Download-->LuaForWindows_v5.1.5-52.exe
安装完成后,cmd--->lua,显示lua版本则成功
2、Sublime Text
https://www.sublimetext.com/download
参考课程:【唐老狮】Unity热更新之Lua语法_哔哩哔哩_bilibili
打印与注释
--单行注释及打印函数
--lua语句 可以省略分号
--[[
实际项目开发,使用的IDE(集成开发环境)
VSCode
IDEA
LuaStudio
使用Sublime Text是因为轻便快捷,且没有代码提示
]]
--print打印函数
print("hello world")
print("测试")
--ctrl+B 运行
--[[
多行注释
]]
--[[
第二种多行
注释
]]--
--[[
第三种多行注释
--]]
变量
--变量
--Lua当中的简单变量类型
--nil number string boolean
--lua中的变量可以随便赋值,自动识别类型
--lua中所有的变量申明的都不需要申明变量类型,会自动判断类型
--类似C#中的var C#中的null
a = nil
print(a)
--number 所有的数值都是number
a = 1
print(a)
a = 1.2
print(a)
--string
a = "12312"
--字符串的声明,使用单引号或双引号包裹
a = '123'
--lua中没有char
--boolean
a = true
print(a)
a = false
print(a)
--通过type函数获得变量的类型
print(type(a))
--type返回值为string
print(type(type(a)))
--lua中使用没有声明过的变量
--不会报错,默认值为nil
print(b)
--[[
函数 function
表 table
数据结构 userdata
协同程序 thread(线程)
]]
String字符串
--字符串
str = "双引号字符串"
str2 = '单引号字符串'
--获取字符串的长度
print(#str) --18
--一个汉字占3个长度
s = "abCD"
--英文字符占1个长度
print(#s) --4
--字符串多行打印
--lua支持转义字符
print("123\n123")
s = [[
多行
进行输
出
]]
print(s)
--字符串拼接 通过..
print("123" .. "456")
s1 = "123456"
s2 = 2
print(s1 .. s2) -- 可以不同类型变量进行拼接
print(string.format("进行了测试,测试了%d次", 20))
--%d:与数字拼接
--%a 与任何字符拼接
--%s 与字符拼接
--别的类型转为字符串
a = true
print(tostring(a))
--字符串提供的公共方法
str = "abCdEfg"
--小写转为大写
print(string.upper(str))
--大写转小写
print(string.lower(str))
--翻转字符串
print(string.reverse(str))
--字符串索引查找
print(string.find(str, "CdE")) --3 5
--lua索引是从1开始
print(string.find(str, "C")) --3 3
--截取字符串
print(string.sub(str, 3)) --从索引开始截取
print(string.sub(str, 3, 4)) --截取两个数字之间
--字符串重复
print(string.rep(str, 2)) --abCdEfgabCdEfg
--字符串修改
print(string.gsub(str, "Cd", "**")) --ab**Efg 1
--字符 转 ASCII码
a = string.byte("Lua", 1) --指定位置字符转为ASCII码
print(a)
--ASCII码 转 字符
print(string.char(a))
--[[
长度获取 #
多行打印 转义字符
字符串拼接 ../string.format %d %s
别的类型转字符串 tostring()
字符串提供的公共方法 upper lower reverse find sub rep gsub字符串修改 sring.byte string.char
]]
运算符Operator
--运算符
--算术运算符
-- + - * / % ^
--没有++ -- 和 复合运算符 += -= *= /= %=
print("加法运算" .. 1 + 2)
a = 1
b = 2
print(a + b)
--字符串可以进行算术运算符,会自动转成number
print("123" + 1) --122
print("123.4" + 1) --122.4
print("减法运算" .. 1 - 2)
print("123" - 1) --124
print("123.4" - 1) --124.4
print("乘法运算" .. 1 * 2) --2
print("123.4" * 2) --246.8
print("除法运算" .. 1 / 2) --0.5
print("123.4" / 2) --61.7
print("取余运算" .. 1 % 2) --1
print("123.4" % 2) --1.4
--lua中,^ 符号是幂运算
print("幂运算" .. 2 ^ 2) --4
print("123.4" ^ 2) --15227.56
--条件运算符
--> < >= <= == ~=(不等于)
print(3>1)
print(3<1)
print(3>=1)
print(3<=1)
--不等于 ~=
print(3==1)
print(3~=1)
--逻辑运算符
--and与 or或 not非
--C# 是&& || ~
--在lua中,也遵循逻辑运算的”短路“规则
print(true and false)
print(true or false)
print(not true)
print(false and print("info")) --短路,直接不执行后面的语句
--位运算符
--不支持位运算,需要自己实现
--C#是& |
--三目运算符
--lua不支持三目运算符
--C#为 a ? b:c
条件分支语句
--条件分支语句
--if else
a = 6
--if 条件 then ... and
--单分支
if a > 5 then
print("123")
end
--双分支
--if 条件 then ... else ... end
if a < 5 then
print("123")
else
print("321")
end
--多分支
--if 条件 ... then ..。 elseif 条件 then ... else ... end
if a < 5 then
print("123")
-- lua中 elseif需要连起来,否则报错
elseif a == 6 then
print("6")
elseif a == 7 then
print("7")
elseif a == 8 then
print("8")
else
print("other")
end
--lua中没有switch语法
if a >= 3 and a <= 9 then
print("3到9之间")
end
循环语句Loop
--循环语句
--while
num = 0
--while 条件 do ... end
while num <= 5 do
print(num)
num = num + 1
end
--do while
--repeat ... until 结束条件
num = 0
repeat
print(num)
num = num + 1
until num > 5 --直到num大于5,跳出 满足条件跳出(结束条件)
--for
--lua默认递增,i默认+1
for i = 1, 5 do
print(i) --1~5
end
for i = 1,5,2 do --如果要自定义增量,直接逗号后面添加
print(i) --输出1 3 5
end
for i = 5,1,-1 do --如果要自定义增量(减少),直接逗号后面添加
print(i) --输出5 4 3 2 1
end
--[[
while 条件 do ... end
repeat ... until 条件
for 变量名=起始值,结束值,增值 do ... end
]]
函数Function
--函数
--从上到下依次读取 lua是解释型语言,逐条读取,逐条执行
--function 函数名()
--end
--a = function()
--end
--无参数无返回值
function f1()
print("f1函数")
end
f1()
f2 = function() --类似C#中的委托和时间
print("f2函数")
end
f2()
--有参数
--如果传入的参数和函数参数个数不匹配,不会报错
--如果没有传入参数,只会补空nil,如果传入多个参数,会丢弃
function f3(a)
print(a)
end
f3(1)
f3("123")
f3("true")
f3() --nil
f3(1,2,3) --1
--有返回值
--多返回值时,在前面申明多个变量来接取即可
--如果变量不够,不受影响,值接取对应位置的返回值
--如果变量多了,直接赋值nil
function f4(a)
return a, "456", true
end
temp = f4("123")
temp1, temp2, temp3, temp4 = f4("123")
print(temp) --123
print(temp1) --123
print(temp2) --456
print(temp3) --true
print(temp4) --nil
--函数的类型
--函数类型为function
f5 = function()
print("123")
end
print(type(f5))
--函数的重载 不支持重载,默认调用最后一个声明的函数
---函数名相同,参数列表不同
function f6()
print("输出信息")
end
function f6(str)
print(str)
end
f6() --输出nil
--变长参数
function f7( ... )
arg = {...}
for i=1,#arg do
print(arg[i])
end
end
f7(1,2,3,4,5,6,7)
f7(1,"123",true,4,5,6)
--函数嵌套
function f8( ... )
return function()
print(123)
end
end
f9 = f8()
f9()
--闭包函数closure
function f10(x)
--改变传入参数的生命周期
return function(y)
return x + y
end
end
f11 = f10(10)
print(f11(5)) --15
--[[
a = function()
function f()
函数传参时,多了会丢弃,少了会补空
外部用多个变量来接取,少了丢弃,多了为nil
函数不支持重载
变长函数 ... 先用表接,再使用
函数嵌套:函数里面声明函数 闭包改变变量声明周期
]]
表Table
--复杂数据类型 Table 迭代器遍历
--所有的复杂类型都是table表
--数组
a = {1, 2, 3, 4, "5", true, nil}
--lua中,索引从1开始
print(a[0])
print(a[1])
--#是通用的获取长度的关键字
--在打印长度时,空被忽略
print(#a)
--数组的遍历
--中间为nil会断掉长度,获取不准确
for i=1,#a do
print(a[i])
end
--二维数组
a = {{1,2,3},{4,5,6}}
print(a[1][1])
print(a[2][3])
--二维数组的遍历
for i=1,#a do
b = a[i]
for j=1,#b do
print(b[j])
end
end
--自定义索引
--忽略小于等于0的索引
aa = {[0] = 1, 2, 3, [-1]=4, 5}
print(aa[0])
print(#aa) --3
bb = {[1] = 1, [2] = 2, [4] = 4, [5] = 5}
print(#bb) --5
--自定义索引跳跃性设置
bb = {[1] = 1, [2] = 2, [5] = 5} --空的多于2个,则只显示前面的,后面的都不要
print(#bb) --2
--迭代器遍历 Pairs
--主要用来遍历表
--#得到的长度,其实并不准确,一般不要用#来遍历表
c = {[0]=1, 2, [-1]=3, 4, 5}
--ipairs
--ipairs遍历,从1开始往后遍历,小于等于0的值得不到
--只能找到连续索引的键,如果中间断序了,无法遍历出后面的内容
for i,k in ipairs(c) do
print("ipairs遍历键值" .. i .. "_" .. k)
end
--pairs迭代器遍历
--能够将所有的键都找到,通过键可以得到值
for i,v in pairs(c) do
print("pairs遍历键值" .. i .. "_" .. v)
end
--[[
ipairs 不能找到0和0以下的自定义索引内容
如果从1开始索引顺序断了,后面的内容也找不到
pairs 建议使用此来遍历各种不规则的表
可以得到所有信息
]]
字典、类和结构体
--复杂数据类型 字典、类和结构体、表的公共操作
--字典
--字典的声明 键值对
a = {["name"]="aaa", ["age"]=18, ["1"]=5}
--访问单个变量,用中括号填键访问
print(a["name"])
print(a["age"])
print(a["1"])
--还可以类似成员变量的形式得到值
print(a.name)
print(a.age)
--虽然可以通过成员变量的形式得到值,但是不能时数字
--print(a.1) --报错
--修改
a["name"] = "BBB"
print(a.name)
--新增
a["sex"] = false
print(a["sex"])
print(a.sex)
--删除
a["sex"] = nil
print(a["sex"])
print(a.sex)
--如果要模拟字典,遍历一定要用pairs
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
--类和结构体
--Lua中默认没有面向对象,需要自己来实现
--成员变量 成员函数
Student = {
--成员变量
age = 1,
sex = true,
--成员函数
Up = function()
--print(age) --nil 这个age和表中age没有任何关系,是一个全局变量
--想要在表内部函数中调用表本身的属性或方法,一定要指定是谁的,使用表名.属性 或 表名.方法
print(Student.age)
print("我成长了")
end,
Learn = function(t)
--在函数内部调用自己属性或方法
--把自己作为一个参数传进来,在内部访问
print(t.sex)
print("我学习了")
end
}
--申明表后,在表外去申明表有的变量和方法
Student.name = "姓名"
Student.Speak = function()
print("说话")
end
function Student:Speak2()
--lua中,关键字self表示
print()
print("说话2")
end
--C# 使用类:实例化对象new 静态
--Lua中类的表现更像是一个中有很多静态变量和函数
print(Student.age)
Student.Up()
Student.Speak()
Student.Speak2()
Student.Learn(Student)
--**Lua中,.和:的区别——冒号调用方法,会默认将调用者作为第一个参数传入方能法中
Student:Learn()
--表的公共操作
t1 = {{name = "123", age = 1}, {name = "456", age = 22}}
t2 = {name = "测试", age = 3}
print(#t1)
--插入
table.insert(t1, t2)
print(#t1)
print(t1[1].name)
print(t1[3].name)
--remove方法,传表进去会移除最后一个索引的内容
table.remove(t1)
print(#t1)
print(t1[1].name)
print(t1[2].name)
print(t1[3])
--第一个参数:要移除内容的表 第二个参数:移除表中内容的索引
table.remove(t1, 1)
print(t1[1].name)
--排序 升序
t3 = {5,2,7,9,5}
table.sort(t3)
for _,v in pairs(t3) do
print(v)
end
--降序 需要排序表,排序规则函数
table.sort(t3, function(a, b)
if a > b then
return true
end
end)
for _,v in pairs(t3) do
print(v)b
end
--拼接
--用于拼接表中元素,返回值为字符串
tb = {"123", "456", "789"}
str = table.concat(tb, ",")
print(str)
多脚本执行
test.lua
print("测试")
test_a = "123456"
local test_b = 789
--将本地变量返回
return test_b
全局变量、局部变量、 _G
--多脚本执行
--全局变量和本地变量
--全局变量
a = 1
b = "123"
for i = 1,2 do
c = "输出"
end
print(c) --c全局全局变量 输出
--局部变量
for i = 1,2 do
local d = "信息"
end
print(d) --nil
fun = function()
tt = "123456"
end
fun()
print(tt) --123456
fun2 = function()
local t2 = "789"
end
fun2()
print(t2) --nil
local t3 = "456789"
print(t3) --456789
--多脚本执行
--关键字 require("脚本名")
--创建Lesson11_test.lua
require("Lesson11_test")
print(test_a) --输出test中全局变量test_a的值
print(test_b) --nil
--脚本卸载
--如果require加载执行的脚本,加载一次后不会再被执行
require("Lesson11_test")
--package.loaded["脚本名"]
--返回值为boolean,该脚本是否被执行
print(package.loaded["Lesson11_test"])
package.loaded["Lesson11_test"] = nil
print(package.loaded["Lesson11_test"])
--执行一个脚本时,可以在脚本最后返回一个外部希望获取的内容
local test_b = require("Lesson11_test")
print(test_bb) --789
--大G表
--_G时是一个总表(table),将我么声明的所有全局变量都存储在其中
for k,v in pairs(_G) do
print(k,v)
end
--本地变量 加了local的变量不会存到大_G表中
--[[
局部变量 local
多脚本执行 require("脚本名")
脚本的最后可以return一个外部希望获取的内容,一般情况下是一个局部变量
脚本卸载 package.loaded["脚本名"] = nil
_G总表,将声明的所有全局变量都存储在其中,加了local的变量不会存在大_G表中
]]
特殊用法
--特殊用法
--多变量赋值
a, b, c = 1, 2, "123"
print(a)
print(b)
print(c)
--后面的值不够,会自动补空
d,e,f = 1, 2
print(d)
print(e)
print(f) --nil
--如果后面值多了,会自动省略
--多返回值
function test()
return 10, 20, 30, 40
end
aa, bb, cc = test()
print(aa)
print(bb)
print(cc)
--and or
--逻辑与 逻辑或
--and or 不仅可以连接boolean,任何类型都可以连接
--在lua中,只有nil和false才认为是假
--短路:对于and,有假则假 对于or,有真则真
--只需要判断第一个是否满足就停止计算
--and 有假直接输出 or 有真直接输出
print(1 and 2) --2
print(nil and 1) --nil
print(false and 1) --false
print(true and 3) --3
print(true or 3) --true
print(false or 5) --5
--lua不支持三目运算符
--但是可以模拟三目运算符
x = 3
y = 2
local temp = (x > y) and x or y
print(temp) --3
元表
--元表
--[[
任何表变量都可以作为另一个表变量的元表
任何表变量都可以有自己的元表
当我们子表中进行了一些特定擦做时,会执行元表中的内容
]]
meta = {}
my_table = {}
setmetatable(my_table, meta)
--特定操作
--__tostring
meta2 = {
--子表被当作字符串使用,会默认调用元表中的__tostring方法
__tostring = function(t) ---子表将自己作为参数传入,打印子表的成员变量
return t.name
end
}
my_table2 = {
name = "姓名"
}
--设置元表函数
-- 参数一:子表 参数二:元表(父表)
setmetatable(my_table2, meta2)
print(my_table2)
--__call
meta3 = {
__tostring = function(t)
return t.name
end,
--子表被当作函数来使用,默认调用__call中的内容
__call = function(a, b)
print(a) --将子表作为参数,执行print,调用__tostring方法,输出t.name
print(b) --1 第二个参数作为
print("子表被作为函数调用")
end
}
my_table3 = {
name = "子表姓名"
}
setmetatable(my_table3, meta3)
my_table3(1) --子表被作为函数调用
--运算符重载
meta4 = {
--add
__add = function(t1, t2)
return t1.age + t2.age
end,
--sub
__sub = function(t1, t2)
return t1.age - t2.age
end,
--mul
__mul = function(t1, t2)
return t1.age * t2.age
end,
--div
__div = function(t1, t2)
return t1.age / t2.age
end,
--mod
__mod = function(t1, t2)
return t1.age % t2.age
end,
--pow
__pow = function(t1, t2)
return t1.age ^ t2.age
end,
--equ
__eq = function(t1, t2)
return t1.age == t2.age
end,
--lt
__lt = function(t1, t2)
return t1.age < t2.age
end,
--le
__le = function(t1, t2)
return t1.age <= t2.age
end,
__concat = function(t1, t2)
return t1.age .. t2.age
end
}
my_table_4_1 = {
age = 3
}
setmetatable(my_table_4_1, meta4)
my_table_4_2 = {
age = 2
}
setmetatable(my_table_4_2, meta4)
print("两个表指定成员变量相加为:" .. my_table_4_1 + my_table_4_2)
print("两个表指定成员变量相减为:" .. my_table_4_1 - my_table_4_2)
print("两个表指定成员变量相乘为:" .. my_table_4_1 * my_table_4_2)
print("两个表指定成员变量相除为:" .. my_table_4_1 / my_table_4_2)
print("两个表指定成员变量取余为:" .. my_table_4_1 % my_table_4_2)
print("两个表指定成员变量幂函数为:" .. my_table_4_1 ^ my_table_4_2)
--如果要用条件运算符比较两个对象,两个对象的元表要一致,才能准确调用
print(my_table_4_1 == my_table_4_2)
print(my_table_4_1 < my_table_4_2)
print(my_table_4_1 <= my_table_4_2)
print("两个表指定成员变量拼接为:" .. my_table_4_1 .. my_table_4_2)
--__index和__newIndex
--__index 当子表中找不到某一个属性时,会到元表中__index指定的表去找索引
meta6 = {}
my_table6 = {}
协程
--协程程序
--协程的创建
--coroutine.create()
fun = function()
print(123)
end
co = coroutine.create(fun)
--协程的本质是一个线程对象
print(co)
print(type(co))
--coroutine.wrap()
co2 = coroutine.wrap(fun)
print(co2)
print(type(co2))
--协程的运行
--第一种 对应通过create创建的协程
coroutine.resume(co)
--第二种 对应wrap的协程
co2()
--协程的挂起
fun2 = function()
local i = 1
while true do
print(i)
i = i + 1
--协程的挂起函数
print(coroutine.status(co3))
coroutine.yield()
return i
end
end
co3 = coroutine.create(fun2)
--默认第一个返回值是协程是否启动成功
--yield里面的返回值
coroutine.resume(co3) --只执行一次
isok, temp1 = coroutine.resume(co3) --只执行一次
print(isok, temp1) --true
co4 = coroutine.wrap(fun2)
--也可以有返回值,只是没有默认第一个返回值
co4()
print("返回值"..co4())
--协程的状态
--[[
coroutine.status(协程对象)
dead 结束
suspended 暂停
running 进行中
]]
print(coroutine.status(co3))
print(coroutine.status(co))
coroutine.running()
--[[
创建协程程序
coroutine.create 返回值为一个thread对象
coroutine.wrap 返回值为一个函数
启动协程
coroutine.resume(协程对象) 默认返回值第一个为是否开启
coroutine.wrap 直接调用函数
协程挂起
coroutine.yield(返回值)
协程的状态
coroutine.status(协程对象或协程函数) dead suspended running
coroutine.running() 返回一个线程编号
]]