当前位置: 首页 > 工具软件 > Lua > 使用案例 >

Lua基础知识整理

向苗宣
2023-12-01

主要记录一些学习过程Lua基础知识

一、Lua中基本类型

1.Lua中基本类型
nil(空), boolean(布尔) ,number(数值) ,string(字符串), function(函数), thread(线程), table(表)

print(type(nil))  --nil
print(type(true)) --boolean
print(type(3))  --number
print(type("Hello world")) --string
print(type(print)) --function
print(type(type)) --thread
print(type({})) --table
  • nil 类型

表示无效值 需要注意的是将nil赋值给全局变量相当于将其删除

  • boolean 类型

true/false 特别注意的是在lua中把0和空字符串视为真
-
可以使用not逻辑运算符进行判断true/false

print(not 0)-- false 则0为真
print(not '')--false 则''为真
  • number类型

lua中整数和浮点型值的类型都是number类型

print(type(1))  --number
print(type(1.11)) --number

需要注意的一点是1.0后边的0不会自动抹去

print(3) --3
print(3.0) --3.0
  • string类型

lua中的string是不可变值 不能直接改变某个字符串中的某个字符
在lua中’ '和" "是等价的 需要注意的是字符串中的第一个字符索引为1

  • 获取字符串长度
    1.使用#+str进行获取长度
    2.使用字符串标准库中的string.len(str)获取长度
a="hello"
print(#a)--5
print(string.len(a))--5
  • 字符串的连接
a="hello"
a.." world" --hello world
print(a)--hello
  • 有字符串参与的算术运算都会被当成浮点运算处理
print("5"+1)--6
  • 字符串标准库中的常用函数
    1.string.len(s) 获取字符串的长度
    2.string.rep(s,n) 返回字符串s重复n次的结果
a="hello"
print(string.rep(a,3))--hellohellohello

3.string.reverse(s,n) 获取字符串的翻转

print(string.reverse("hello"))--olleh

4.**string.lower(s)**将字符串中的大写字母都转换成小写函数string.upper(s)与其相反
5.string.sub(s,i,j) 从字符串s中提取第i个到第j个字符(包括第i个和第j个字符)

a="hello"
print(string.sub(a,2,4))--ell
print(a)--hello
print(string.sub(a,2,-2))--ell -2表示倒着数第二个字符

6.string.format() 对字符串格式化和将数值输出为字符串

a=10
b=11
str1="Hello"
str2="world"
print(string.format("a=%d b=%d",a,b))--a=10 b=11
print(string.format("%s%s",str1,str2))--Helloworld

7.string.find(s,t) 在s中查找t字符串 如果找到返回索引否则返回nil

str1="Hello"
print(string.find(str1,"ell"))--2  4
print(string.find(str1,'l')) --3  3 只能查找一个
print(string.find(str1,'aw')) --nil

8.string.gsub(s,t,w) 将s中的所有t字符串替换为w 返回替换后的字符串和替换次数

str1="Hello"
print(string.gsub(str1,'l','w'))--Hewwo	2
print(string.gsub(str1,'i','n'))--Hello	0
  1. string.match(s,t) 返回匹配的字符串t
print(string.match("hello world","hw"))--nil
print(string.match("hello world","hello"))--hello
  • table类型

table(表)是Lua的一种数据结构可以用来创建数组,字典等 table中默认初始索引为1
1.表的构建

mytable={}--初始化表
mytable["str1"]="str"
mytable[2]=23;
print(mytable.str1) --str
print(mytable["str1"])--str
print(mytable[2]) --23
days={"str1","str2","str2"}
print(days[1]) --str1

2.遍历表
使用pairs迭代器遍历表

tab={"I",a=1,b=2,"as"}
for k,v in pairs(tab) do
   print(k,v)
   --1 I
   --2 as
   --a 1
   --b 2  
end

4.table标准库

  • table.concat(table[,sep[,i[,j]]]) 返回table[i]…sep…table[i+1]…sep…table[j]
tab={"I","asd","we","as"}
print(table.concat(tab,"."))--I.asd.we.as
print(table.concat(tab,".",2))--asd.we.as
print(table.concat(tab,".",2,3))--asd.we
  • table.insert(table,[pos,]value) 插入数据
tab={"I","asd","we","as"}
table.insert(tab,"xx")--默认插入末尾
for k,v in pairs(tab) do
    io.write(v.." ")--I asd we as xx
end
table.insert(tab,1,"m")--插入首部
for k,v in pairs(tab) do
    io.write(v.." ")--m I asd we as xx
end
  • table.maxn(table) 返回最大索引值
tab={"I","asd","we","as","awqe"}
print(table.maxn(tab))--5
  • table.remove(table[,pos]) 移除数据
tab={"I","asd","we","as","awqe"}
table.remove(tab)--默认移除最后一个
for k,v in pairs(tab) do
    io.write(v.." ")--I asd we as
end
table.remove(tab,2)
for k,v in pairs(tab) do
    io.write(v.." ")--I we as
end
tab={12,3,2,4,6,44}
table.sort(tab)
for k,v in pairs(tab) do
    io.write(v.." ")--2 3 4 6 12 44
end
table.sort(tab,function(a,b)
   return a>b
end)
for k,v in pairs(tab) do
    io.write(v.." ")--44 12 6 4 3 2
end

function(函数)

  • 函数的构造
function functionName(...)
end
--匿名函数
function(...)
end
  • 多个返回值
function Foo(a,b)
   return a,b
end
a,b,c=Foo(10,11)--当接收参数大于返回参数时会对后续接收参数赋值为nil
print(a.." "..b) --10 11
print(c)--nil
b=nil
a=Foo(10,11) --按顺序进行接收未接收的数据进行舍弃
print(a)--10
  • 可变长参数函数
    用…组成的表达式称为可变长参数表达式
function myF(...)
    local a,b=...
	print(a.." "..b)--1 2
end
myF(1,2,34,4)
  • 使用select函数进行获取可变长参数的个数
function myF(...)
    local a,b=...
	print(select("#",...))--4
	print(select(2,...))--2,34,4 返回第n个及以后的值
end
myF(1,2,34,4)
--闭包现象---
 - [未理解原理] 

在运行时,每当Lua执行一个形如function…end 这样的表达式时,就会创建一个新的数据对象,
其中包含了相应函数原型的引用及一个由所有upvalue引用组成的数组,而这个数据对象就称为闭包。
闭包是由一个函数和该函数会访问到的非局部变量(或者是upvalue)组成的
function myFunction()
  local c=0
  return function()
             c=c+1--词法定界使子函数能够访问主函数的值
			 return c
		  end
end
c1=myFunction()
print(c1())--1
print(c1())--2
c2=myFunction()
print(c2())--1
print(c1())--3

二、关系运算

  >  <  >=  <=  ==   ~=(不等于)

三、逻辑运算符and or not

  • and
    a and b 如果a 为false类型则返回a 否则返回b
a=false
b=10
c=1
d=nil
print(a and b) --false
print(c and b) --10
print(d and b) --nil
  • or
    a or b 如果a为true则返回a 否则返回b
a=false
b=10
c=1
print(a or b) --10
print(c or b) --1
  • not
    使用not 运算符返回的值均为boolean类型
print(not nil)--true
print(not 0)--false
  • Lua中的三元运算
    关于a?b:c可以使用and or 的连用进行实现功能
x=19
y=10
z=21
print((x>y) and x or y) --19 先and运算 后or
print((x>z) and x or z) --21

四、流程控制以及循环

流程控制

  • 需要注意lua中认为false和nil为false true和非nil为true
  • 结构
condition=10
if (condition>10) then
    print("大于")
elseif (condition==10) then
    print("等于")
else
	print("xiao于")
end

循环

  • while循环
语法
while(condition) do --当condition为true时执行
    myfun()
end
a=10
while(a>0) do
  io.write(a.." ")--10 9 8 7 6 5 4 3 2 1
  a=a-1
end
  • for循环
语法
for var=exp1,exp2,exp3 do --var从exp1变化到exp2每次变化以exp3为步长默认exp3为1 
    myfun()
end
for i=1,10 do
   io.write(i.." ")--1 2 3 4 5 6 7 8 9 10 
end
  • repeat…until
    相当于其他语言do{ }while(condition)语句
    唯一不同的是do{}while()条件为假时跳出
    而repeat…until是条件为真时跳出
语法
repeat
   <执行块>
until(condition)
a=1
repeat
  print(a.." ")--1 2 3
  a=a+1
until(a>3)

五、数据结构

  • 数组

使用#求数组长度是需要注意的是它只能用于序列(所有元素不为nil的列表)

--构建数组
array1={}
for i=1,10 do
   array1[i]=i
end
for i=1,10 do
    print(array1[i])-1 2 3 4 5 6 7 8 9 10
end
--求数组长度
print(#array1)-10
array1[5]=nil
print(#array1)--10
array1[20]=1
print(#array1)--10
array2={1,2,3,nil,nil}
print(#array2)--3
  • 矩阵

第一种方式创建矩阵
function createMetrax_1(M,N)
    local mt={}
    for i=1,M do
      local row={}
	  mt[i]=row
	  for j=1,N do
	    row[j]=0
	  end
	end
	return mt
end
--第二中方式创建矩阵
function createMetrax_2(M,N)
    local mt={}
    for i=1,M do
      local index=(i-1)*N
	  for j=1,N do
	    mt[index+j]=0
	  end
	end
	return mt
end
function printMetra(mt)
  for i=1,#mt do
    for j=1,#mt[1] do
	   io.write(mt[i][j]..',')
	end
	print()
  end
end
mt1=createMetrax_1(5,2)
printMetra(mt1)
mt2=createMetrax_2(5,3)
print(#mt2)--15
  • 链表

lis={next=nil,value=nil}--创建链表
function createLink(list)
    head=list
	repeat
	   x=io.read()
	   list1={next=nil,value=x}
	   head.next=list1
	   head=head.next
	until(x=='a')
end
function InsertData(lits,i,n)--在第i个插入n
    local t=1
	local head=lits
	while(t<i) do
        head=head.next
		t=t+1
	end
	temp={next=head.next,value=n}
	head.next=temp
end
function printLink(link)
   l=link.next
   while l do
      io.write(l.value..",")
	  l=l.next
   end
   print()
end
createLink(lis)
printLink(lis)--1,2,3,4,a
InsertData(lis,3,22)
printLink(lis)--1,2,22,3,4,a
stack1={bottom=1,top=0}--创建栈
function push(stack,n)--入栈
   stack.top=stack.top+1
   stack[stack.top]=n
end
function pop(stack)--出栈 未进行安全判断
   local value=stack[stack.top]
   stack.top=stack.top-1
   return value
end
push(stack1,1)
push(stack1,2)
for i=1,stack1.top do
   io.write(stack1[i]..",")
end
print()
pop(stack1)
for i=1,stack1.top do
   io.write(stack1[i]..",")
end

六、模块与包

模块就是一些可以被require加载的代码,创建和返回一个表。然后根据表调用里面的内容。使用require加载的代码相当于引用命名空间。

--Lua1.lua
re=require "module" --这里的re相当于模块中的module表
print(re.val)
re.func_1()
--re.func_2()--不能直接调用模块中的局部方法
re.func_3()
--module.lua
module={}
module.func_1=function()
   print("调用模块中的 func_1方法")
end
module.val=10
local function func_2()
    print("调用模块中的局部函数")
end
function module.func_3()
    print("调用模块中的func_3")
    func_2()
end
return module

七、元表

定义:元表是一个普通的lua表,定义了原始值的某些特殊操作下的行为。可以通过在其元表中设置特定字段来更改对值的操作行为。
例如:当一个非数字值进行加法操作数时,Lua会检查其元表中的“__add”字段中的函数,通过调用这个函数执行加法

  • setmetatable(table,metatable) 对table设置元表,如果元表中存在__metatable键值则会设置失败
  • getmetatable(table) 返回对象的元表
--设置元表
mytable={}--普通表
mymetatable={}--元表
setmetatable(mytable,mymetatable)--把mymetatable设为mytable的元表

元方法

元方法是指元表事件中的键和值如上述加法中事件是“add”,元方法是执行加法的函数。

  • 算术元方法
    __add(+) 、__sub(-)、__mul(*)、 __div(/)、 __mod(%)、 __concat(…) 、__eq(==)
    这里只对__add进行举例
    当一个非数字值进行加法操作数时,Lua会检查其元表中的“__add”字段中的函数,通过调用这个函数执行加法
--实现两个表数据的相加
--对mytable设置元表
mytable=setmetatable({10,12,13},{__add=function(mytable,table2)
   local temp={}
   for i=1,#mytable do
        if i<=#table2 then
          temp[i]=mytable[i]+table2[i]
        end
   end
   if #mytable>#table2 then
       for i=#table2+1,#mytable do
	      temp[i]=mytable[i]
	   end
    elseif #mytable<#table2 then
	    for i=#mytable+1,#table2 do
	      temp[i]=table2[i]
	   end
	end
	return temp
end})
tabl={1,2,3,4}
temp=mytable+tabl
for i=1,#temp do
   print(temp[i])--11 14 16 4
end
  • __index元方法
    官方定义:The indexing access table[key].(索引访问表)
    就是通过键值访问表中的数据 如果这个键值不存在原表中,则就会寻找元表中__index元方法,在__index中查找键值—相当于继承
mytable=setmetatable({"st",key_1="value_1"},{__index={key="value",le="asd",
func_1=function()
  print("调用func_1方法")
end}})
print(mytable.key_1)--value_1
print(mytable.key)--value
mytable.func_1()--调用func_1方法
  • __newindex元方法
    主要功能给原表中未存在的索引赋值,此时会查找__newindex元方法
    给未存在键进行赋值时并未给原先的表添加数据而是在元表中添加数据
    如果需要访问通过元表访问而__index元方法解决了此问题
mymetatable={}--元表
mytable=setmetatable({key1="value1"},{__newindex=mymetatable})--进行设置元表
print(mytable.key1)
mytable.newkey="newvalue"
print(mytable.newkey,mymetatable.newkey)--nil newvalue
mytable.key1="value_1"
print(mytable.key1,mymetatable.key1)--value_1 nil
--修改版本1.0 添加__index元表使原表可以访问存储在元表中的值
mymetatable={}--元表
mytable=setmetatable({key1="value1"},{__index=mymetatable,__newindex=mymetatable})--进行设置元表
print(mytable.key1)
mytable.newkey="newvalue"
print(mytable.newkey,mymetatable.newkey)--newvalue newvalue
mytable.key1="value_1"
print(mytable.key1,mymetatable.key1)--value_1 nil
--通过rawset(t,k,v)函数进行更新表可以绕过元方法
mytable=setmetatable({key1="value1"},{__newindex=function(mytable,key,value)
    rawset(mytable,key,value)
end})
mytable.key2="value2"
mytable.key1="new value"
print(mytable.key1,mytable.key2)--new value  value2
  • 案例
    通过代理创建只读的表
function readOnly(t)
     local agent={}--代理表
     local mt={
	    __index=t,
		__newindex=function(t,k,v)
          error("this is a only read table")
		end
	 }
	 setmetatable(agent,mt)--为代理表设置
	 return agent
end
test=readOnly({"red","or","blue"})
print(test[1])--red
test[2]="white"--lua: LuaStudy_1.lua:140: this is a only read table
--主要是agent表中并没数据,数据存储在元表中
--对其进行赋值时不管是否存在键值都会调用其元表中的__newindex方法
  • __tostring元方法
    主要作用是修改表的输出行为相当于c#中的重写tostring功能
mytable=setmetatable({key1="this",key2="is",key3="a",key4="joke!"},
{__tostring=function(mytable)
     local temp=''
	 for k,v in pairs(mytable) do
	    temp=temp..v.." "
	 end
	 return temp
end})
print(mytable)--this a joke! is
关于为什么没按照键值输出 主要是lua中数组(表)也没有顺序
--顺序遍历表
--主要方法是将表中的键进行排序 pair遍历表时键会随机的顺序出现
function pairsSort(t)
     local a={}
     for k in pairs(t) do
        a[#a+1]=k
     end
     table.sort(a)
     local i=0
     return function()--这里涉及闭包概念。。。
              i=i+1
              return a[i],t[a[i]]
	         end
end
mytable={key1="this",key2="is",key3="a",key4="joke!"}
for k,v in pairsSort(mytable) do
   print(v) -- this is a joke!
end

八、面向对象

lua中的对象是由table+function组成
面向对象的特征封装、继承、多态、抽象
首先看一个简单的类的例子

Algorithm={result=0}--元类
--基础基方法 相当于其他语言中new方法
function Algorithm:new(o)--使用: 隐藏self参数
   o=o or {} --o相当于对象中的原表 
   setmetatable(o,self)--设置元表 self是指对象
   self.__index=self--self 相当于其他语言中的this 将对象本身添加到__index元方法中
   return o
end
--基础类方法
function Algorithm:printResult(x,y)--运算方法
	print(self.result)
end
function Algorithm:test()
   print(self.key1)
end
myal=Algorithm:new(nil)--创建对象
myal:printResult(1,2)--0
myval=Algorithm:new({key1="value1",key2="value2"})
print(myval.key1)--value1
myval:test()--value1
  • 继承
加法类
AddAlgorithm=Algorithm:new()
function AddAlgorithm:new(o)
   o=o or Algorithm:new()
   setmetatable(o,self)
   self.__index=self
   return o
end
--重写
function AddAlgorithm:printResult(x,y)
     self.result=x+y
	 print(x.."+"..y.."="..self.result)
end
--减法类
SubAlgorithm=Algorithm:new()
function SubAlgorithm:new(o)
    o=o or Algorithm:new()
   setmetatable(o,self)
    self.__index=self
    return o
end
function SubAlgorithm:printResult(x,y)
    self.result=x-y
	print(x.."-"..y.."="..self.result)
end
--乘法类
MulAlgorithm=Algorithm:new()
function MulAlgorithm:new(o)
  o=o or Algorithm:new()
  setmetatable(o,self)
  self.__index=self
  return o
end
function MulAlgorithm:printResult(x,y)
    self.result=x*y
	print(x.."*"..y.."="..self.result)
end
addt=AddAlgorithm:new(nil)
subt=SubAlgorithm:new(nil)
mult=MulAlgorithm:new(nil)
addt:printResult(1,2)--1+2=3
subt:printResult(1,2)--1-2=-1
mult:printResult(1,2)--1*2=2
mult:test()--调用父类中的test()
  • 单方法对象
    将方法以对象的表示形式返回
  function GetSet(value)
     return function(action,v)
         if action=="get" then return value
         elseif action=="set" then value=v
         end
        end
  end
  test=GetSet(0)--此时test就是function(action,v)对象
  print(test("get"))--0
  test("set",10)
  print(d("get"))--10
  • 私有性
    主要是根据返回的表进行调用方法 而且只有返回表中有的才能调用
--这里的self表以及subData都是私有的外界不可访问
function Algorithm(data)
    local self={balance=data}
    local addData=function(v)
	   self.balance=self.balance+v
	end
	local subData=function(v)
       self.balance=self.balance-v
	end
	local getBalance=function()
	   return self.balance
	end
	return {addData=addData,getBalance=getBalance}
end
test=Algorithm(10)
test.addData(10)
print(test.getBalance())--20

九、协程

Lua 中的协程代表一个独立的执行线程
线程与协程的主要区別在于,一个多线程程序可以并行运行多个线程,而协程在任意指定的时刻只能有一个协程运行。

方法描述
coroutine.create(f)创建一个协程 其中f必须是一个函数。并返回一个类型为线程的对象
coroutine.resume(co[,val1,…])开始或继续执行协程 co
coroutine.status(co)以字符串形式返回协程 co 的状态挂起(suspended),运行(running),正常(normal),死亡(dead)
coroutine.wrap(f)创建一个新的协程,主体为 f。 f 必须是一个函数。返回一个函数,该函数在每次调用时恢复协程
coroutine.yield(…)暂停调用协程的执行
还有个coroutine.yieldable()官方解释Returns true when the running coroutine can yield.
和coroutine.running()返回正在运行的协程 不知道如何用【TODO】
  • 协程的创建以及开始(唤醒)
--当协程处于yield状态时需要重新唤醒协程
第一种创建协程方法
co=coroutine.create(function(x,y)
 coroutine.yield(x,y)
 print("yield..")
 return x,y
end)
print(coroutine.status(co))--suspended挂起状态
print(coroutine.resume(co,1,2))--true 1 2
print(coroutine.status(co))--suspended
xx,a,b=coroutine.resume(co)--yield..
print(xx,a,b)--true 1 2
第二种创建协程的方法 使用wrap创建协程时不需要resume启动
cp=coroutine.wrap(function()
   print("cp")
   coroutine.yield()
   print("cp1")
end)
print(type(cp))--function
cp()--cp
cp()--cp1

math库常用函数

  • math.abs(x) 获取绝对值
  • math.ceil(x) 获取大于或等于x的最小整数
print(math.ceil(2.1))--3
  • math.floor(x) 获取小于或等于x的最大整数
print(math.floor(2.1)) --2
  • math.cos(x) 获取余弦值 其中x传入为弧度
print(math.cos(1.0/3*math.pi)) --0.5
  • math.deg(x) 将x 从弧度转化为角度
print(math.deg(1.0/6*math.pi))--30
  • math.rad(x) 从角度转化为弧度
  • math.modf(x) 返回x的整数部分和小数部分 第二个结果总是浮点数
print(math.modf(10.0)) --10   0
print(math.modf(10.1)) --10  0.1
  • math.pi 圆周率
  • math.random([m[,n]]) 随机数
print(math.random())--返回一个[0,1]之间的浮点数
print(math.random(2,4))--返回一个[2,4]之间的整数
print(math.random(10))--返回1-10之间的整数
  • math.tointeger(x) 转化为整数 如果可以转化返回整数否则返回nil
math.tointeger(10.1)-- nil
math.tointeger(10)--10
math.tointeger('')--nil
  • math.type(x) 判断float 或int类型
math.type(10.1)--float
math.type(10)--integer
math.type('')--nil

以上内容参考–Lua程序设计第4版–菜鸟教程Lua–Lua5.3 Reference Manual

 类似资料: