Lua(0)环境搭建与基础代码

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() 返回一个线程编号
]]

上一篇:硬件设计细节1-缓冲驱动器使用注意事项-三、结论


下一篇:yolo-world:”目标检测届大模型“