Lua 是动态语言,变量没有类型,值才有。值自身携带类型信息。
Lua 有八种基本数据类型:
nil, boolean,number,string,function,userdata, thread,table
仅 nil 和 false 导致条件为假,其他均为真。
--获取变量类型***************************************************
print(type(a))
pirnt(type(type(a)))--type本身返回的是string
--空类型,所有未赋值的变量,默认值为nil
a=nil
--number类型******************************************************
a=1
a=1.2
--string类型******************************************************
a="12312"
a='123'
s="skjeDlEL字符串"--一个汉字占3个长度,英文占一个
print(#s)--#获取字符串长度
print("123\n456")--支持转义字符
s=[[
sdkjfei
skeioe
]]
print(s)--支持多行字符串
print("123".."456")--字符串拼接1
s1=111
s2=111
print(s1..s2)--字符串拼接2
print(string.format("我今年%d岁了",18))--字符串拼接3
--%d:与数字拼接
--%a:与任何字符拼接
--%s:与字符配对
a=true
s=tostring(a)--其他类型转字符串
print(s)
str="abCDeFg"
--小写转大写
print(string.upper(str))
--大写转大写
print(string.lower(str))
--翻转字符串
print(string.reverse(str))
--字符产索引查找
print(string.find(str,"CDe"))
--截取字符串
print(string.sub(str,3,4))
print(string.sub(str,3))
--字符串重复
print(string.rep(str,2))
--字符串修改
print(string.gsub(str,"CD","**"))
--字符转ASCII码
a=string.byte("Lua",1)
print(a)
--ASCII码 转字符
print(string.char(a))
--算数运算符*********************************************************
-- + - * / %
--没有自增自减 ++ --
--没有复合运算符 += -= /= *= %=
--字符串可以进行算数运算符操作,会自动转为number
a=1
b=2
print("加法运算"..a+b)
print("123.4"+1)
print("减法运算"..a-b)
print("123.4"-1)
print("乘法运算"..1*2)
print("123.4"*2)
print("除法运算"..1/2)
print("123.4"/2)
print("取余运算"..1%2)
print("123.4"%2)
print("幂运算"..2^5)
print("123.4"^2)
--条件运算符*******************************************************
-- > < >= == ~=
print(3>1)
print(3<1)
print(3>=1)
print(3<=1)
print(3==1)
--不等于 是 ~=
print(3~=1)
--逻辑运算符*******************************************************
--&& || !(与下面对应)
--and or not
print(true and false)
print(true and true)
print(true or false)
print(true or false)
print( not true)
a=7
--if 条件 then.....end
--单分支
if a>5 then
print("123")
end
--双分支
if a<5 then
print("123")
else
print("321")
end
--多分支 elseif必须连着,中间无空格
if a<5 then
print("123")
elseif a==6 then
print("6")
elseif a==7 then
print("7")
elseif a==8 then
print("8")
elseif a==9 then
print("9")
end
if a>=4 and a<=9 then
print("4到9之间")
end
print("**************while语句***************")
num=0
--while 条件 do.....end
while num<5 do
print(num)
num=num+1
end
print("**************do while语句***************")
num=0
--repeat......until 条件 (注意:条件是结束条件)
repeat
print(num)
num=num+1
until num>5 --满足条件跳出 结束条件
print("****************for语句***************")
for i=2,5 do --默认递增 i会默认+1
print(i)
end
for i=1,5,2 do --如果要自定义增量,直接逗号后面写
print(i)
end
for i=5,1,-1 do
print(i)
end
print("***********函数**********")
--function 函数名()
--end
--a=function()
--end
print("********无参无返回值*********")
--函数在声明前不能调用
function F1()
print("F1函数")
end
F1()
--有点类似 C#中的 委托和事件
F2=function()
print("F2函数")
end
F2()
print("************有参数************")
function F3(a)
print("参数:"..tostring(a))
end
F3(1)
F3("123")
F3(true)
--如果你传入的参数 和函数参数的个数不匹配
--不会报错 只会补空nil 或者 丢弃
F3()
F3(1,2,3)
print("************有返回值************")
function F4(a)
return a,"123",true
end
--多返回值时,在前面声明多个变量来接取
--如果变量不够 不影响 值接取对应位置的返回值
--如果变量多了 不影响 直接赋nil
temp,temp2,temp3,temp4=F4("123")
print(temp)
print(temp2)
print(temp3)
print(temp4)
print("*************函数的类型************")
F5=function ()
print("123")
end
print(type(F5))
print("*************函数的重载***********")
--lua中 默认调用最后一个声明的函数
function F6()
print("456")
end
function F6(str)
print("456"..str)
end
print("************变长参数**************")
function F7(...)
--变长参数使用 用一个表存起来 再用
arg={...}
for i=1,#arg do
print(arg[i])
end
end
F7(1,"123",true,4,5,6)
print("***********函数嵌套**************")
function F8()
return function()
print(123)
end
end
f9=F8()
f9()
--闭包
function F9(x)
--改变传入参数的声明周期
return function(y)
return x+y
end
end
f10=F9(10)
print(f10(6))
print("****************复杂数据类型****************")
--所有的复杂类型都是table(表)
print("********************数组*****************")
a={1,2,"123",nil,5,6,7,true,nil}
--lua中 索引从1开始
print(a[0])
print(a[3])
print(a[9])
--#是通用的获取长度的关键字
--在打印长度的时候,空被忽略
--如果表中(数组中)某一位变成nil,会影响#获取的长度
print(#a)
print("********************数组的遍历*****************")
for i=1,#a do
print(a[i])
end
print("********************二维数组*****************")
a={{1,2,3},{4,5,6},{7,8,9}}
print(a[2][1])
print(a[3][2])
print("********************二维数组的遍历*****************")
for i=1,#a do
b=a[i]
for j=1,#b do
print(b[j])
end
end
print("********************自定义索引*****************")
aa={[0]=1,2,3,[-1]=4,5}
print(aa[0])
print(aa[-1])
print(aa[1])
print(aa[2])
print(aa[3])
print(#aa)--只从1开始计算
aa={[1]=1,[2]=2,[4]=4,[6]=5}
print(#aa)
for i=1,#aa do
print(aa[i])
end
print("**********迭代器遍历*************")
--迭代器遍历 主要用来遍历表的
--#得到长度,其实并不准确 一般不要用#来遍历表
a={[0]=1,2,[-1]=3,4,5,[5]=6}
print("***********ipairs迭代器遍历*****************")
--ipairs
--ipairs遍历 还是 从1开始往后遍历的 小于等于0的值得不到
--只能找到连续索引的键 如果中间短序了 它也无法遍历出后面的内容
for i,k in ipairs(a) do
print("ipairs遍历键值"..i.."_"..k)
end
print("**************pairs迭代器遍历***************")
--它能够把所有的键都找到 通过键可以得到值
for i,v in pairs(a) do
print("pairs遍历键值"..i.."_"..v)
end
print("**************pairs迭代器遍历键***************")
for i in pairs(a) do
print("pairs遍历键"..i)
end
print("*****************字典的声明*****************")
--字典是由键值对构成
a={["name"]="小明1",["age"]=14,["1"]=5}
--访问当个变量 用中括号填键 来访问
print(a["name"])
print(a["age"])
print(a["1"])
--还可以用 .成员变量的形式得到值,但是不能是数字
print(a.name)
print(a.age)
print(a["1"])
--修改
a["name"]="ABC"
print(a["name"])
print(a.name)
--新增
a["sex"]=false
print(a["sex"])
print(a.sex)
--删除
a["sex"]=nil
print(a["sex"])
print(a.sex)
print("****************字典的遍历*****************")
--如果要模拟子弹,遍历一定用pairs
for k,v in ipairs(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
print("*****************类和结构体*****************")
--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
}
--声明表过后,在表外去声明表有的变量和方法
Student.name="CDE"
Student.speak=function()
print("说话")
end
--函数的第三种声明方式
function Student.speak2()
print("说话2")
end
--C#要是使用类 实例化对象new 静态 和.
--lua中类的表现 更像是类中有很多静态变量和函数
print(Student.age)
print(Student.name)
--调用Student函数
Student.up()
Student.speak()
Student.speak2()
Student.learn(Student)
--lua中 .和冒号的区别
--冒号调用方法 会默认把调用者 作为第一个参数传入方法中
Student:learn()
function Student:speak3()
--lua中 有一个关键字 self 表示默认传入的第一个参数
print(self.name.."说话")
print("说话2")
end
Student:speak3()
Student.speak3(Student)
print("********************表的公共操作****************")
--表中 table提供的一些公共方方法的讲解
t1={{age=1,name="123"},{age=2,name="345"}}
t2={name="ABC",sex=true}
print("********************插入****************")
--插入
print(#t1)
table.insert(t1,t2)
print(#t1)
print(t1[1])
print(t1[2])
print(t1[3])
print(t1[3].sex)
print("********************移除****************")
--删除指定元素
--remove方法 传表进去 会移除最后一个索引的内容
table.remove(t1)
print(#t1)
print(t1[1].name)
print(t1[2].name)
print(t1[3])
--remove方法 传两个参数 第一个参数 是要移除内容的表
--第二个参数 是要移除内容的索引
table.remove(t1,1)
print(t1[1].name)
print(#t1)
print("***********排序**************")
t2={5,2,7,9,5}
--传入的两个参数 第一个是用于排序的表
--第二个是 排序规则函数
--默认从小到大
table.sort(t2)
for _,v in pairs(t2) do
print(v)
end
--降序
table.sort( t2, function(a,b)
if a>b then
return true
end
end)
for _,v in pairs(t2) do
print(v)
end
print("************拼接*************")
tb={"123","456","988","34895"}
--连接函数 用于拼接表中元素 返回值 是一个字符串
str=table.concat(tb,",")
print(str)
Test脚本
print("Test测试")
testA="123"
local testLoaclA="456"
return testLoaclA
print("************全局变量和本地变量***************")
--全局变量
a=1
b="123"
for i=1,2 do
c="ABC"
end
print(c)
--本地(局部)变量的关键字
for i=1,2 do
local d="ABC"
print("循环中的d"..d)
end
print(d)
fun=function()
local tt="45934852097"
end
fun()
print(tt)
print("************多脚本执行*****************")
--关键字 require("") require('')
require("Test")
print(testA)
print(testLoaclA)
print("******************脚本卸载****************")
--如果是require加载执行的脚本,加载一次之后不会再被执行
require('Test')
--package.loaded["脚本名"]
--返回值时boolean 意识是 该脚本是否被执行
print(package.loaded["Test"])
--卸载已经执行过的脚本
package.loaded["Test"]=nil
print(package.loaded["Test"])
--require 执行一个脚本时 可以在脚本最后返回一个外部希望获取的内容
local testLa= require("Test")
print(testLa)
print("****************大G表*******************")
--_G表 是一个总表(table) 它将我们声明的所有全局变量都存储在大G表
for k,v in pairs(_G) do
print(k,v)
end
--本地变量 加了local的变量是不会存到大_G表中
print("************多变量赋值********")
a,b,c=1,2,"123"
print(a)
print(b)
print(c)
--多变量赋值 如果后年的值不够,会自动补空
a,b,c=1,2
print(a)
print(b)
print(c)--nil
--多变量赋值 如果后面的值多了 会自动省略
a,b,c=1,2,"123",24,5,6,3,2
print(a)
print(b)
print(c)
print("************多返回值********")
function test()
return 10,20,30,40
end
--多返回值时,用几个变量接,就有几个值
--如果少了 就少接几个 如果多了 就自动补空
a,b,c=test()
print(a)
print(b)
print(c)
a,b,c,d,e=test()
print(a)
print(b)
print(c)
print(d)
print(e)
print("***************and or***************")
--逻辑与 逻辑或
--and or 他们不仅可以连接 boolean 任何东西都可以用来连接
-- 在lua中 只有nil和false才认为是假
--"短路" ——对于and来说 有假则假 对于 or来说 有真则真
--所以 他们只需要判断 第一个 是否满足 就会停止计算了
print(1 and 2) --输出2
print(0 and 1) --输出1
print(nil and 1) --输出nil
print(false and 2)--输出false
print(true and 3) --输出3
print(true or 1) --输出true
print(false or 1)--输出1
print(nil or 2) --输出2
--lua不支持三目运算符
x=3
y=2
-- ?:
local res=(x>y) and x or y
print(res)
--(x>y) and x————> x
--x or y————> x
--(x>y) and x————>(x>y)
--(x>y) or y————>y
print("****************协程的创建******************")
fun=function()
print(123)
end
co=coroutine.create(function()
print(123)
end)
--协程的本质是一个线程对象
print(co)
print(type(co))--打印thread
--coroutine.wrap()
co2= coroutine.wrap(fun)
print(co2)
print(type(co2))--打印function
print("****************协程的运行******************")
--第一种方式 对应的 是通过 create创建的协程
coroutine.resume(co)
--第二中方式 对应的 是通过 wrap创建的协程
co2()
print("****************协程的挂起******************")
fun2=function()
local i=1
while true do
print(i)
i=i+1
--协程的挂起函数
print(coroutine.status(co3))--打印running
print(coroutine.running())--打印当前运行的线程号
coroutine.yield(i)
end
end
co3=coroutine.create(fun2)
--默认第一个返回值 是 协程是否启动成功
--yield里面的返回值
isOK, tempI= coroutine.resume(co3)
print(isOK,tempI)--打印 true 2
isOK, tempI=coroutine.resume(co3)
print(isOK,tempI)--打印 true 3
isOK, tempI=coroutine.resume(co3)
print(isOK,tempI)--打印 true 4
co4=coroutine.wrap(fun2)
--这种方式的协程调用 也可以有返回值 只是没有默认第一份返回值了
print("返回值"..co4())
print("返回值"..co4())
print("返回值"..co4())
print("****************协程的状态******************")
--coroutine.status(协程对象)
--dead 结束
--suspended 暂停
--running 进行中
print(coroutine.status(co3))
print(coroutine.status(co))
--这个函数可以得到当前正在 运行的协程的线程号
print(coroutine.running())
print("*****************元表概念*******************")
--任何表变量都可以作为另一个表变量的元表
--任何表变量都可以有自己的元表(爸爸)
--当我们子表中进行一些特定操作时
--会执行元表中的内容
print("*****************设置元表*******************")
meta={}
myTable={}
--设置元表函数
--第一个参数 子表
--第二个参数 元表
setmetatable(myTable,meta)
print("*****************特定操作-__tostring*******************")
meta2={
--当子表要被当做字符串使用时 会默认调用元表中的tostring方法
__tostring=function(t)
return t.name
end
}
myTable2={
name="ABCD"
}
--设置元表函数
--第一个参数 字表
--第二个参数 元表(爸爸)
setmetatable(myTable2,meta2)
print(myTable2)--打印ABCD
print("*****************特定操作-__call*******************")
meta3={
--当子表要被当做字符串使用时 会默认调用元表中的tostring方法
__tostring=function(t)
return t.name.."1"
end,
--当子表被当做一个函数来使用时 会默认调用__call中的内容
--当希望传参数时 一定要记住 默认第一个蚕食 是调用者自己
__call=function(a,b)
print(a)
print(b)
print("A")
end
}
myTable3={
age=12,
name="ABCD"
}
setmetatable(myTable3,meta3)
--把子表当做当做函数使用 就会调用原表的__call方法
myTable3(1)--打印ABCD1 1 A
print("*****************特定操作-运算符重载*******************")
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 6
end,
--运算符/
__div=function(t1,t2)
return 0
end,
--运算符%
__mod=function(t1,t2)
return 2
end,
--运算符^
__pow=function(t1,t2)
return 1
end,
--运算符==
__eq=function(t1,t2)
return true
end,
--运算符<
__lt=function(t1,t2)
return false
end,
--运算符<=
__le=function(t1,t2)
return true
end,
--运算符..
__concat=function(t1,t2)
return "123"
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)
print("*****************特定操作-__index和__newIndex*******************")
meta6Father={
age=1
}
meta6Father.__index=meta6Father
meta6={
--age=1,
--__index=meta6
}
--__index的赋值 写在表外面来初始化
meta6.__index=meta6
myTable6={
--age=2
}
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)--打印为1
--rawset 该方法会忽略newindex的设置 只会改自己的变量
rawset(myTable7,"age",2)
print(myTable7.age)
封装
print("***************封装******************")
--面向对象 类 其实都是基于 table来实现
--元表相关的知识点
Object={}
Object.id=1
function Object:Test()
print(self.id)
end
--冒号 是会自动将调用这个函数的对象 作为第一个参数传入的写法
--为表Object添加方法new()
function Object:new()
--self 代表的是 我们默认传入的第一个参数
--对象就是变量 返回一个新的变量
--返回出去的内容 本质上就是表对象
local obj={}
--元表知识 __index 当找自己的变量 找不到时 就会去找元表当中__index指向的内容
self.__index=self
setmetatable(obj,self)
return obj
end
local myObj=Object:new()
print(myObj)
print(myObj.id)
myObj:Test()
--对空表中 声明一个新的属性 叫做id
myObj.id=2
print(Object.id)--打印1
myObj:Test()--打印2
继承
print("***************继承******************")
--C# class 类名 : 继承类
--写一个用于继承的方法
function Object:subClass(className)
--_G知识点 是总表 所有声明的全局变量 都以键值对的形式存在其中
_G[className]={}
--写相关继承的规则
--用到元表
local obj=_G[className]
self.__index=self
--子类 定义一个base属性 base属性代表父类
obj.base=self
setmetatable(obj,self)
end
--print(_G)
--_G["a"]=1
--_G.b="123"
--print(a)
--print(b)
Object:subClass("Person")
local p1=Person:new()
print(p1.id)
p1.id=100
print(p1.id)--打印100
local p2=Person:new()
p2.id=101
print(p2.id)--打印101
Object:subClass("Monster")
local m1=Monster:new()
print(m1.id)
m1.id=200
print(m1.id)
多态
--相同行为 不同表现 就是多态
--相同方法 不同执行逻辑 就是多态
Object:subClass("GameObject")
GameObject.posX=0;
GameObject.posY=0
function GameObject:Move()
self.posX=self.posX+1
self.posY=self.posY+1
print(self.posX)
print(self.posY)
end
GameObject:subClass("Player")
function Player:Move()
--base 指的是GameObject表(类)
--self.base:Move()这种方式调用 相当于是把基类表 作为第一个参数传入了方法中
--避免把基类表传入到方法中 这样相当于就是公用一张表的属性了
--我们如果要执行父类逻辑 我们不要直接使用冒号调用
--要通过.调用 然后自己传入第一个参数
self.base.Move(self)
end
local p1=Player:new()
p1:Move()
p1:Move()
--这种写法有坑 不同对象使用的成员变量 居然是相同的成员变量
--不是自己的
local p2=Player:new()
p2:Move()
--面向对象实现
--万物支付 所有对象的基类 Object
--封装
Object={}
--实例化方法
function Object:new()
local obj={}
--给空对象设置元表,以及 __index
self.__index=self
setmetatable(obj,self)
return obj
end
--继承
function Object:subClass(className)
--根据名字生成一张表 就是一个类
_G[className]={}
local obj=_G[className]
--设置自己的“父类”
obj.base=self
--给子类设置元表 以及__index
self.__index=self
setmetatable(obj,self)
end
--声明一个新的类
Object:subClass("GameObject")
--成员变量
GameObject.posX=0
GameObject.posY=0
--成员方法
function GameObject:Move()
self.posX=self.posX+1
self.posY=self.posY+1
end
--实例化对象使用
local obj=GameObject:new()
print(obj.posX)
obj:Move()
print(obj.posX)
local obj2=GameObject:new()
print(obj2.posX)
obj2:Move()
print(obj2.posX)
--声明一个新的类 Player 继承GameObject
GameObject:subClass("Player")
--多态 重写了 GameObject的Move方法
function Player:Move()
--base调用父类方法 用.自己传第一个参数
self.base.Move(self)
end
--实例化Player对象
local p1=Player:new()
print(p1.posX)
p1:Move()
print(p1.posY)
local p2=Player:new()
print(p2.posX)
p2:Move()
print(p2.posY)
print("**************自带库*****************")
--string
--table
print("***************时间******************")
--系统时间
print(os.time())
--自己传入参数 得到时间
print(os.time({year=2014,month=8,day=14}))
--os.date("*t")
local nowTime=os.date("*t")
for k,v in pairs(nowTime) do
print(k,v)
end
print(nowTime.hour)
print("***************数学运算***************")
--math
--绝对值
print(math.abs(-11))
--弧度转角度
print(math.deg(math.pi))
--三角函数 传弧度
print(math.cos(math.pi))
--向下向上取整
print(math.floor(2.6))
print(math.ceil(5.2))
--最大最小值
print(math.max(1,2))
print(math.min(4,5))
--小数分离
print(math.modf(1.2))
--幂运算
print(math.pow(2,5))
--随机数
--先设置随机数种子
math.randomseed(os.time())
print(math.random(100))--第一个数不变,受种子影响
print(math.random(100))
--开方
print(math.sqrt(4))
print("***************路径***************")
--lua脚本加载路径
print(package.path)
package.path=package.path..";C:\\"
print(package.path)
print("***************垃圾回收***************")
test={id=1,name="123123"}
--垃圾回收关键字
--collectgarbage
--获取当前lua占用内存数 K字节 用返回值 就可以得到具体的内存占用字节数
print(collectgarbage("count"))
--lua中的机制和C#中垃圾回收机制很类似 解除羁绊 就是变垃圾
test=nil
--进行垃圾回收 理解有点像C#的GC
collectgarbage("collect")
print(collectgarbage("count"))
--lua中 有自动定时进行GC的方法
--Unity中热更新开发 尽量不要去用自动垃圾回收