Lua学习笔记
程序员文章站
2022-03-14 11:00:01
...
最近准备把lua应用到之前写过的Unity项目中,所以先学一下Lua,在这里做点笔记,自己没事翻翻看就好。
lua学习记录
lua的变量类型 nil string number boolean table(“表”,lua的面向对象由表实现) function userdata thread(表示执行的独立线程,本质是伪“多线程”,是协程的概念,用于执行协同程序)
判断语句短路规则
真&&假 假
假&&真 假
num1&&num2 num2
真||假 真
假||真 真
num1||num2 num1
多重赋值 num1,num2,num3 = 10,20,30
在语句块中添加local才是局部变量
eg.
do
local num = 1 (局部变量)
end
ipairs与pairs迭代器
ipairs迭代数组、遍历顺序集合,遇到nil就会中断
pairs迭代表、遍历集合中的所有数据
使用pairs关键字,循环输出数据、字符串类型时,for中必须使用k、v,循环中的k、v可以是任何字母或者合法的标识符代替
lua标准库提供的迭代器
A.迭代文件每行的io.lines
B.迭代table的pairs
C.迭代数组元素得的ipairs
D.迭代字符串中单词的string.gmatch
lua函数function
函数格式
function function_name( ... )
-- body
end
lua函数的性质
1.函数无需定义返回类型,可以返回任意类型与任意数量的数值
2.函数的参数,无需定义参数类型
3.函数无需大括号
4.可以定义变量,把函数直接赋值给它,从而获得相同功能(类似与C#的委托)
eg.
1.不带返回值
function func1(a)
end
2.带返回值
function func2( a,b)
return a+b
end
3.函数赋值给变量
func3 = func2
--因为func2有返回值
result1 = func3(20,30)
print(""..result1)
warning:定义函数 函数中由于函数没有参数类型,所以在没有(编译)运行前,计算机是无法发现错误的,这对比其他编译语言是一个明显的弱点
local关键字,全局与局部变量
lua规定,默认变量都是全局变量(无论是否定义在语句块中),局部变量需要在代码块中用local修饰
eg.
function func4( )
gNum1 = 10 --全局变量num1
local num2 = 20 --使用local定义局部变量num2
end
fun4()
print(gNum1) --输出10
print(num2) --报错无法输出,num2是nil值
在函数中定义全局变量,在函数外照样可以访问
函数可以声明为全局的与局部的,默认是全局的
eg.
local function locFunc( ... )
-- body
end
local函数不能被别的lua文件调用,类似于类中的private方法
函数的多返回值
可以返回多个任意不同类型的数值
eg.
function GetNumb( ... )
return 10,20,30,(40)
end
res1,res2,res3,(res4) = GetNumb()
函数的多返回值性质:
1.如果一个函数调用在最后,或者仅有一个表达式,lua回保留尽可能多的返回数值用于匹配
2.如果一个函数没有返回值,或者没有足够多的返回值,那么lua会用nul来补充缺失数值
函数可以作为数据进行赋值,也可以作为参数进行传递(类似于C#的委托)
函数作为参数进行传递
eg.
function PrintInfo( res )
print("")
print(res)
end
function AddNum(num1,num2,printFunc)
local result = num1+num2
printFunc(result)
end
匿名函数
定义:没有函数名称的函数
一个没有名称的函数,只有通过赋值给一个变量(相当于C#的委托注册方法),通过调用这个函数变量来间接调用这个匿名函数
定义的时候,无需定义函数名称,但是一定要把匿名函数赋值给变量
eg.
hideFunc = function (num1,num2)
--匿名函数
print(num1+num2)
end
hideFunc(66,88) --调用匿名函数,本质是调用的是匿名函数赋值给的变量
Lua字符串
字符串的下标从1开始
字符串的三种表示方式
str1= " "
str2= ' '
str3=[[ ]] --适合大量字符串
str4=" ' ' " --可以在双引号里面带单引号
str5=' " " '--单引号里面可以带双引号
string.len(str1) --使用字符串函数,输出字符串长度
#str2 --使用#符号,输出字符串长度
转义字符串
常用的,回车 \r 换行 \n 反斜杠 \\ 双引号 ""
字符串常用函数
A:字符串长度len()、大小写函数upper()、lower()
string.len(str)
string.upper(str)
string.lower(str)
B:查找函数find()
string.find(s,pattern,init,plain)
findPos = string.find(str,"a") --str是搜索的源字符串,"a"表示搜索关键字
findPos = string.find(str,"a",5) --"5"参数表示从下标5的位置开始搜索
C:截取函数 sub()
string.sub(s,i,j) --s是源字符串,i是选择截取字符串的位置,j是截取j个字符
strSubResult = string.sub("HelloWorld",1,3)
strSubResult = string.sub("朋友们好,Hello!",1,4) --汉字是两个占位符
D:字符串替换函数 gsub()
strGSubResult = string.gsub(s,pattern,repl,n) --s源字符串,pattern关键字,repl替换后的关键字,n
E:字符串反转 reverse()
strReverseResult = string.reverse(s) --s源字符串
--> abcd ==> dcba
F:格式化字符串 format()
传统输出多个变量的长字符串,使用“拼接”的方式
eg.
num1,num2,num3 = 10,20,30
--输出三个变量相加的结果
print("加法:num1:"..num1.." +num2"..num2.." +num3:"..num3.." result="..num1+num2+num3)
访问数据库的开发
print("select 列名? from 表明? where id = ?查询条件? and ...") --查询数据库的语句
--简化以上长字符串中添加多个变量问题的写法,lua提供了“字符串格式化”函数
eg.
--%d 表示一个数值型变量
--%s 表示一个字符串变量
string.format()
strFormatResult = string.format(formatstring:"使用字符串格式化:num1: %d+num2: %d+num3: %d = result: %d",num1,num2,num3,num1+num2+num3) --formatstring需要格式化的字符串
表
Table是lua的一种数据结构,用来帮助我们创建不同的数据类型,如数组、键值对集合等。。
表的特征与定义
lua(数组)的下标可以是负数,lua的长度可以动态改变(与C#的固定长度数组不同),可以把lua数组认为是C#的List、dictionary等集合类型
把Table当成一个"字典"集合来对待,也可以当成一个"数组"来对待,这要看如何初始化表
Table集合,可以有“空表”,“直接声明且定义表内容”,“声明表然后逐一赋值”三种方式
Table集合,也可以定义成类似“数组”的定义方式,其访问可以使用下标进行访问(但是lua没有数组概念,用表来表示)
访问table中的数据(键值对集合),可以直接用“.”访问,也可以用中括号访问,但一定要加字符串,否则会报错
Table中的索引都是由1开始的
tabMyArray = {} --定义表
print(tabMyArray) --输出表的地址
--定义数组类型的表
tabMyArray1 = {11,111,333} --相当于数组
print(tabMyArray1[1]) --使用下标,进行表的内容输出
print(tabMyArray1[2])
print(tabMyArray1[3])
--下标是从1开始的 要是tabMyArray1[0] 则会输出nil
--定义键值对类型的表
tabMyArray3 = {str1="aaa",str2="bbb",str3="ccc"}
--输出键值对类型的表
--两种不同的输出方式
1.使用中括号输出
print(tabMyArray3["str1"]) --输出信息
2.使用“.”输出,类似于C#中输出属性
print(tabMyArray3.str2)
print(tabMyArray3.str3)
表的赋值与迭代输出
1.空表的赋值与迭代输出 --空表要赋值才能输出
2.字典类型表的赋值与迭代输出
3.关于表变量的相互赋值的技术(引用传递)
lua中的table相当于c#中的字典类集合(具备key/value键值对的数据结构)
lua表的遍历方式
[table.getn();表示集合中的数量,即集合中最大索引]
for i =1,table.getn(mytable) do
...
end
for i,v in pairs(mytable) do
print(i,v)
end
tabMyArray4 = {10,20,30,54,40}
--使用for输出
for i =1 ,4 do
print(tabMyArray4[i])
end
--使用table函数或者符号输出
for i =1 ,#tabMyArray4 do --使用“#”符号,来得到表中的数量
print(tabMyArray4[i])
end
for i=1 , table.getn(tabMyArray4) do --使用表函数table.getn(tableName),得到表中的数量
print(tabMyArray4[i])
end
--使用迭代输出(键值对类型)
tabMyArray5= {str1="aaa",str2="bbb",str3="ccc"}
tabMyArray5.str4 = "ddd"
tabMyArray5["str5"] = "eee"
--输出
for i =1,5 do --需要注意,getn和 # 只能用于数组,键值对还是需要给定长度
print(tabMyArray5["str"..i]) --不常用也不实用
end
使用迭代器函数 pairs / ipairs 输出连续与非连序(键值对)数值
--输出顺序不能保证
tabMyArray6 = {str1="aaa",str2="bbb",str3="ccc"}
for k,v in pairs(tabMyArray6) do
print(k,v) --k键 v值 --key value
end
一般数组类型的集合可以只输出v,即只输出数据,但是 k,v还是必须的。
tabMyArray7={"aa","bbb","c"}
for k,v in ipairs(tabMyArray7) do
print(v)
end
表的函数
table.getn():得到表(数组型)的长度
tab1= {"aa","bbb","c"}
得到表的长度 # 和table.getn都可以都可以得到数组型表的长度
eg.
print(#tab1)
print(table.getn(tab1))
table.concat():高效率的对于字符串链接的一种方式
eg.
tab2 = {"aa","bbb","c"}
str2 = table.concat(tab2)
print("str2="..str2) --print : str2=aabbbc
str3 = table.concat(tab2,"|") --添加分隔符
print("str3="..str3) --print : str2=aa|bbb|c
str4 = table.concat(tab2,"|",2,3) --指定序号内容字符串 2到3
print("str4="..str4) --print : str2=bbb|c
table.insert(t,pos,value) --t表,pos位置,value值
eg.
tab3 = {"Hell","Every"}
table.insert(tab3,2,"o ")
print(table.concat( tab3)) --print : Hello Every
tab4 = {"同学","大家好"}
table.insert(tab4,2,"们,")
print(table.concat( tab4)) --print : 同学们,大家好
table.remove()
tab5 = {"Hello ","Everyone","OK"}
table.remove(tab5) --函数默认移除最后的字符串序号
print(table.concat( tab5)) --print :Hello Everyone
table.remove(tab5,2) --这样就把Everyone删除了
print(table.concat( tab5)) --print :Hello OK
table.sort() 表的排序方法
needSortTable = {10,32,21,54,97,84,32,45,8}
table.sort( needSortTable ) --升序排列
--输出查看
for i =1,table.getn(needSortTable) do
print(needSortTable[i])
end
--字符串排序
needSortStrTable = {"river","sky","Cave","好","World"}
table.sort(needSortStrTable)
for i=1,table.getn(needSortStrTable) do
print(needSortStrTable[i]) --print :Cave World river sky 好 顺序是大写 小写 中文
end
得到表中最大数值 lua 5.1好像有bug
table.maxn() 得到表中的最大正数索引值,返回的是key值
tabMaxAarry = {10,32,21,54,97,84,32,45,8}
nMaxNum = table.maxn(tabMaxAarry)
print("表中最大数值 = "..nMaxNum)
寻找最大值函数
---输入:tableName,表类型变量 (如果不合法则输出nil)
---输出:表中的最大值key值,以及对应的value
function GetTableMaxNumb(tableName)
--建议在函数块内使用局部变量
local returnMaxNumber = nil --返回最大数值
--参数检查
if(type(tableName)~="table") then --type()返回值是个字符串
print("error table")
return nil
end
for k,v in pairs(table) do
--给returnMaxNumber变量赋予初始数值
if(returenMaxNumber ==nil) then
returnMaxNumber = v
end
--取得表中得最大数值
if(v>returnMaxNumber) then
returnMaxNumber = v
end
end
return returnMaxNumber
end
resultMaxNum = GetTableMaxNumb(tabMaxAarry)
if(resultMaxNum~=nil) then
print(resultMaxNum)
else
print("nil")
end
表资源的释放
使用nil对表(字符串、基本其他数据类型)资源作释放
给整个table赋值nil,则表示销毁整个表,清空内存
tabMaxAarry = nil --释放变量资源
resultMaxNum = nil
lua模拟面向对象编程
OOP三大特性,封装,继承,多态
封装:指能够把一个实体的信息、功能、响应都装入一个单独的对象中的特性
继承:继承的方法允许在不改动源程序的基础上对其进行扩充,这样使得原功能得以保存,而新功能也得以扩展。有利于减少重复编码,提高软件的开发效率
多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果
lua的语法没有面向对象机制
lua中使用Table实现面向对象机制。把table模拟成一个“类”来使用。
其实lua的string(math、random)等就可以看成面向对象的特殊表
定义表的字段与方法
tableName.field 定义表的字段与方法使用
tableName.methodName()定义表的字段与方法
定义表的第二种方式,匿名方法赋值给表字段
eg. --定义一个空表,相当于一个OOP编程中得“类”
Person = {}
--定义字段
Person.Name = "陈治翰"
Person.Gender = "男"
Person.Weight = 51
Person.Height = 173
--定义方法
Person.Speak = function ( ) ---第一种定义方式 匿名函数
print("人在说话")
end
function Person.Walking() --第二种定义方式 常用的定义方法
print("人在走路")
end
--在方法中调用信息 传统定义方式
Person.ShowInfo = function ( )
print("调用个人信息")
print("身高"..Person.Height) --记得要加Person
print("体重"..Person.Weight)
Person.Speak()
person.Walking()
end
--在方法中调用信息 改进函数定义方式使用局部变量
--引入this变量
local this = Person
Person.ShowInfo = function ( )
print("调用个人信息")
print("身高"..this.Height) --记得要加Person
print("体重"..this.Weight)
this.Speak()
this.Walking()
end
调用表中"字段"与"方法"
--调用字段
print(Person.Name) --print :陈治翰
print(Person.Gender) --print :男
print(Person.Weight) --print :51
print(Person.Height) --print :173
--调用方法
Person.Speak()
Person.Walking()
--提高函数的灵活性
a=Person --把Person表复制给a 变量
a.ShowInfo() --也可以执行的
Person=nil --把Person销毁了
a.ShowInfo() --会报错,Person是空对象
--要是定义了local this = Person
a.ShowInfo() --正常执行了
表字段的缺陷
定义局部表引用变量,降低方法引用表字段的耦合性 --使用self关键字 就可以不使用局部变量了
在lua中,可以认为定义的Person表,Person是一个指针,那么定义的Person表的内容在内存的其他区域。当Person赋值给a,就相当于又定义了一个a指针,就相当于有a、Person两个指针指向Person的内容,
当Person = nil 只是把Person这个指针销毁了,但是Person中的内容还在。在销毁之前,使用a获取Person的内容,则需要定义一个其他局部变量,相当于第三个指针,该指针指向Person的内容。但是在Person表中,
需要用第三个指针调用Person的字段和函数
使用self关键字完善方法定义和调用方式
使用self关键字,直接在方法中引用表自身的字段与方法
--在方法中调用信息 继续改进函数定义方式使用局部变量(配合函数使用“冒号”定义函数)
--使用自带的self关键字
function Person:Show( )
print("调用个人信息")
print("身高"..self.Height) --记得要加Person
print("体重"..self.Weight)
self.Speak()
self.Walking()
end
--调用
Person:Show() --更加完善与常用的方法的调用方式