Lua语法


内容转自b站up主唐老狮

环境搭建以及第一个lua程序

环境安装

luaForWindows
环境下载地址,选择download
在这里插入图片描述
然后找一下release版本的.exe文件加载就可以,一路Next就可以安装成功
我们可以来到cmd输入lua,出现以下情况即说明输入成功
在这里插入图片描述

IDE

这里只使用Sublime Text用来学习
中文版下载地址
这里如果中文版地址进不去,也可以下载英文版然后汉化
在这里插入图片描述
我们在桌面新建一个文件夹,新建一个txt,把后缀改成lua
在这里插入图片描述
这里用sublimeText打开
写一个最简单的打印语句,这里不需要分号结尾,按Ctr+B运行

在这里插入图片描述

在线工具

在线工具:lua在线工具
在线体验luatOS->lua测试
在这里插入图片描述

变量

我们可以先在sub里打开文件夹,选择我们要的文件夹
在这里插入图片描述

分类

简单的4种变量类型

  • number
  • string
  • boolean
  • nil

复杂的4种变量类型

  • function
  • table
  • userdata
  • thread

nil

类似于C#中的null

number

lua中所有的数值类型都是number

string

字符串拼接

print(string.format("因为我刚满%d岁", 18))--输出18

小写转大写+大写转小写

str="sdASC"
print(string.upper(str))--返回一个新的字符串,而不是修改原有字符串

str"ABC"
print(string.lower(str))--返回一个新的字符串,而不是修改原有字符串

翻转字符串

str="abc"
print(string.reverse(str))--返回一个新的字符串,而不是修改原有字符串

字符串索引查找

str="abcdefg"
print(string.find(str,"cde"))
--输出 3	5 说明lua是多返回值的,并且初始索引是1

截取字符串

str="abcdefg"
print(string.sub(str,3,4))

字符串重复

str="abc"
print(string.rep(str,2))--如果是2就是输出abcabc,是3输出abcabcabc

字符串修改

str="abc"
print(string.gsub(str,"ab","**"))--输出**c,1 1是指重复一次,如果str等于abcab 那么就会输出2

字符转ASCII码

print(string.byte("lua",1))--输出108

运算符

算数运算符

lua中没有++ – += /=这种运算符
加减乘除都和正常的高级语言相似,这里说一下lua中的幂运算

print("幂运算"..":"..2^10)

条件运算符

Lua中的不等于操作是~=
与操作是and
或操作是or
非操作是not

位运算符和三目运算符

lua不支持

条件分支语句

基础语法

a=9
if a>5 then
	a=10
end
print(a)

加else

a=9
if a<5 then
	a=10
else 
	a=99
end
print(a)

加else if的操作,注意lua中要写成elseif

a=9
if a<5 then
	a=10
elseif a==9 then
	a=99
end
print(a)

lua没有switch

循环

while语句

a=10
while a<15 do
a=a+1
end
print(a) 

do while语句
和其他语言do while不一样的是lua的函数尾判断的是跳出条件

a=10
repeat 
	a=a-1
until a<5 --在小于5时跳出
print(a)

for循环

for i=2,5 do--这里其实隐藏了+1的显式声明,所以如果想每次+2就要改成i=2,5,2
	print(i)
end

函数

基本声明

function f1()
	print("调用函数")
end
f1()

a = function ()
    print("调用函数")
end
a()

然后是对应传入参数的情况

function f1(a )
	print(a)
end
f1(1)--输出1
f1("aaa")--输出aaa
f1()--输出nil
f1(2,3,4)--输出2

然后是针对于lua的参数返回值,最后输出1

function f1(a)
	return a,"abc",1
end
c=f1(1)
print(c)

但是如果想把f1的返回值都接住,就要采取如下方式,就可以返回三个了

function f1(a)
	return a,"abc",1
end
c,d,e=f1(1)
print(c,d,e)

lua不支持函数重载,会调用最后声明的函数

接下来是变长参数
使用变长参数必须要用表把这个存起来

function F7(...)
	arg={...}
	for i=1,#arg
	do
		print(arg[i])
	end
end
F7(1,2,3,4,5,6,7)

最后我们来讲函数嵌套

function F8()
	F9=function()
		print(123)
	end
	return F9
end

f9=F8()
f9()

然后看一个比较复杂的案例

function F9(x)
	return function(y)
		return x+y
	end
end
f10=F9(10)
print(f10(5))--输出15

所有的复杂类型都是表
这里我们先声明一个table,然后打印一下

a={1,2,"asda",true,nil}
for i=1,#a do
	print(a[i])
end

发现程序没有打印nil,并且输出大小也只有4
在这里插入图片描述
如果把数组改成这样,这里lua5.15似乎更改了逻辑,在数组中出现nil不会视为中断数组

a={1,2,nil,4,"1231",true,nil}
print(#a)//输出2
b={1,nil,2,4,"1231",true,nil}
print(#b)//输出6

二维数组

a={{1,2,3},{4,5,6}}
for i=1,#a do
	for j=1,#a[1] do
		print(a[i][j])
	end
end

表支持自定义索引

a={[0]=1,2,3,[-1]=4}
print(a[0])
print(a[-1])
a={[0]=1,2,3,[-1]=4}
print(a[0])
print(a[1])
print(a[2])
print(a[3])
print(a[4])
print(#a)

输出
在这里插入图片描述

迭代器遍历

主要是用来遍历表
ipairs

a={[0]=1,2,3,4,[-1]=3,[5]=6}
for i,k in ipairs(a) do
	print(i.."_"..k)
end

输出
1_2
2_3
3_4
这里可以发现,ipairs遍历从1开始往后遍历,小于等于0的值得不到
并且只能遍历连续索引,断序之后没办法遍历出后面的内容
我们现在的代码只需要把ipairs改成pair
然后输出看看
1_2
2_3
3_4
0_1
-1_3
5_6
可以发现这次把非常规序的在后面输出出来了

基本语法

a={["name"]="DIO",["age"]=14,["1"]=5}
print(a.name) --访问
print(a["age"]) --访问
a.name="dio" --修改
print(a.name)
a["stand"]="TheWorld"--新增
print(a.stand)
--可以用修改的逻辑来达到删除的目的,只是把内容写成nil就可以

输出:
在这里插入图片描述
接下来是遍历字典,要用pairs来遍历

for k,v in pairs(a) do
print(k,v)
end

输出:
在这里插入图片描述

lua中是没有面向对象的概念的,需要自己去实现类
这里说是类其实可以当成一个数组来看,我们写一个类(数组),拥有成员变量和成员函数

Student={
    --年龄
    age=18,
    --性别
    sex=1,
    study=function() --类内声明函数
    print("学习")
        end,
    love=function()
    print("恋爱")
    end
}
Student.speak=function() --类外声明函数
print("说话")
end
Student.speak()

这里有一点要注意

Student={
    --年龄
    age=18,
    study=function()
    print(age)
    end
}
Student.study()

这里不会输出18,Student类的age和study函数里打印的age不是一个,正确做法应该是

 print(Student.age)

或者是用这种方法

Student={
    --年龄
    age=18,
   learn=function(t)
   print(t.age)
   end
}
Student.learn(Student)

这里就要介绍“ . ”和“ ”的区别
使用冒号可以默认把调用者作为参数传入函数中

Student={
    --年龄
    age=18,
   learn=function(t)
   print(t.age)
   end
}
Student:learn()--只是把.改成冒号而已

表的公共操作

t1={{age=1,name="123"},{age=2,name="345"}}
t2={name="Theshy",sex=1}

print("插入前的t1长度".." "..#t1)
table.insert(t1, t2)--插入操作
print("插入后的t1长度".." "..#t1)

table.remove(t1)--正常情况下是应该有第二个参数的,如果没有就移除最后被添进来的
print("删除后的t1长度".." "..#t1)

table.table.remove(t1, 2)--移除指定位置

table.sort(t2) --排序

table.sort(t2,function(a,b) --在sort中实现类似lambda表达式的效果实现降序
if a>b then
return true
end
end
)

tb={"123","456","789","10101"}--表的拼接
str=table.concat(tb,",")
print(str)

多脚本执行相关概念

在Lua中默认都是全局变量,所以需要用local来设置为临时变量
现在的问题是多脚本运行是如何的呢?
首先我们先搞一个测试脚本
这个脚本有如下语句

--TestScript
print("我是测试脚本")
function f1()
print("我是测试函数")
end

如果想在另一个脚本调用测试脚本的东西应该怎么办呢

--主脚本
require("TestScript")--单引号也行

这样就会执行测试脚本的功能了
require是有返回值的,前提是其他脚本返回了一个值,这样可以在主脚本使用其他脚本的全局变量
但是如果再执行一次require(“TestScript”)没有效果,因为脚本只会加载一次

package.loaded("脚本名")--可以用来检测是否被加载过

所以我们同样可以使用这个语句来实现脚本卸载

package.loaded("脚本名")=nil --再执行require就有效果了

大G表

大G表存的是全局变量(不存本地变量)以及其他一些东西

特殊用法

多变量赋值

少了补空

a,b,c=1,2
print(a)--输出1
print(b)--输出2
print(c)--输出nil

多了丢弃

a,b,c=1,2,3,4,5
print(a)--输出1
print(b)--输出2
print(c)--输出3

多返回值

这里和前面相似,我用一个函数返回多返回值然后用变量去接
少了补空多了丢弃

或和与

and是有假则假,只有遇到nil或false才会认为假

print(1 and 2)
print(0 and 1)
print(nil and 1)
print(false and 2)
print(true and 3)
print(nil and 0)
print(false and nil)
print(nil and false)

在这里插入图片描述
对于or来说有真则真

print(true or 1)
print(false or 1)
print(nil or 2)

在这里插入图片描述

用and 和 or 实现三目运算符

x=3
y=2
z=x>y and x or y

协程

使用create创建一个协程

f1=function()
print(123)
end
co=coroutine.create(f1)--常用方式

协程的本质是一个线程,可以通过type(co)查看
使用wrap创建一个协程,注意,使用wrap创建的协程本质上是函数

f1=function()
print(123)
end
co2=coroutine.wrap(f1)

协程的执行

f1=function()
print(123)
end
f2=function()
print(456)
end

co=coroutine.create(f1)
co2=coroutine.wrap(f2)

coroutine.resume(f1)
f2()--由于第二种是函数,直接调用即可

协程的挂起

这里由于在死循环中挂起了,现在只调用一次resume所以只会输出一个123

f2=function()
while true do
print(123)
coroutine.yield()--协程的挂起
end
end

co3=coroutine.create(f2)
coroutine.resume(co3)

协程的状态

f1=function()
print(123)
print(coroutine.status(c1))
end

c1=coroutine.create(f1)
print(coroutine.status(c1))
--coroutine.yield(f1)
--print(coroutine.status(c1))--报错
coroutine.resume(c1)
print(coroutine.status(c1))

输出
在这里插入图片描述

元表

概念

任何表变量都可以作为另一个表变量的元表
任何表变量都可以有自己的元表
当我们在子表(有元表的表)进行一些特定的操作时
会执行元表中的内容

设置元表

meta={}
myTable={}
--设置元表函数
setmetatable(myTable, meta)--第一个参数子表 第二个参数元表
}

__tostring

接下来要注意,使用的函数名必须为__tostring,是两个下划线,少一个都不行,起其他名字也不行
当子表要被当作字符串使用时,会默认调用这个元表中的__tostring方法

meta2 = {
    _tostring = function()
        return "啦啦啦"
    end
}
mytable2 = {}
setmetatable(mytable2, meta2)
print(mytable2)

__call

当子表要被当作函数使用时,会默认调用这个元表中的__call方法

meta2 = {
    __call = function()
        return "啦啦啦"
    end
}

mytable2 = {}
setmetatable(mytable2, meta2)
print(mytable2())

输出啦啦啦
例2

meta2 = {
    __call = function(self, b)
        print(self.name)  -- 输出表中的name字段
        print(b)
    end
}

mytable2 = { name = "喀喀喀" }
setmetatable(mytable2, meta2)

-- 调用表时只传入一个参数
mytable2(1)

输出喀喀喀,1

运算符重载

__add

metaAdd={
    __add=function(t1,t2)
    return 5
    end
}

table1={}
table2={}

setmetatable(table1, metaAdd)

print(table1+metaAdd)--输出5
print(table1+table2)--输出5

这里只是举add的例子,剩下有很多元表运算符重载可以自行查询
如果要用条件运算符来比较两个对象
这两个对象的元表一定要一致,才能准确调用方法
例如t1和t2分别有不同元表,此时t1==t2可能会产生错误结果,只有t1和t2共享相同元表结果才能准确

__index

__index 当子表中找不到某一个属性时
会到元表中 __index指定的表去找索引

metaIndex = {
 
}
metaIndex.__index={age=2}

table1 = {}
setmetatable(table1, metaIndex)

print(table1.age)  -- 输出 2

接下来是嵌套
这里table找age找不到,来到元表找,元表也找不到,所以去元表的元表找

metaIndexGrandFather={
    age=2
}
metaIndexGrandFather.__index=metaIndexGrandFather

metaIndexFather={

}
metaIndexFather.__index=metaIndexFather

metaIndextable={}
setmetatable(metaIndexFather, metaIndexGrandFather)
setmetatable(metaIndextable, metaIndexFather)

print(metaIndextable.age)

__newindex

当赋值时,如果赋值一个不存在的索引,那么会把这个值赋给newindex所指的表中,不会修改自己

meta={}
--meta.__newindex={}
table1={}
setmetatable(table1,meta)
table1.age=1
print(table1.age)

如果我保留注释,那么将会输出1,但是如果我把注释取消,那么会输出nil,因为newindex改变了table1寻找age的路径

如果使用rawset,则会忽略__newIndex的设置,只会改自己的变量
同理,rawget会忽略index

面向对象

封装

这里我定义了一个Object类,希望达到高级语言类似实例化的效果,但是Lua中没提供这个,所以需要我们自己实现
所以核心逻辑是声明一个子表,然后把需要实例化的类声明为元表,如果通过子表访问数据没有,通过__index将位置指到元表,就可以正常访问了

Object={}
Object.id=1

function Object:new()
	local obj={}
	self.___index=self
	setmetatable(obj,self)
	return Object
end
local myobj=Object:new()
print(myobj.id)

继承

我们接着在上面代码的基础上声明一个继承函数
这里使用_G用于在全局声明数组,并且把新创建的表设置成元表

Object={}
Object.id=1

function Object:subClass(className)
	_G[className]={}
	local  obj = _G[className]
	self.__index=self
	setmetatable(obj,self)
	--return obj
end

Object:subClass("LaLaLa")
print(LaLaLa.id)

多态

这里如果不声明Player的move方法,那么结果就是1,1,如果声明了就什么都不会输出

Object={}
Object.id=1

function Object:subClass(className)
	_G[className]={}
	local obj = _G[className]
	self.__index=self
	setmetatable(obj,self)
	return obj
end

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()
end

local p1=Player:subClass("Player")
p1:Move()

但是现在有一个问题,我确实可以通过多态实现相同函数不同的调用逻辑,但是子类现在要如何调用父类的同名函数?
方法就是在继承时额外加一个base的字段用来保存父类

function Object:subClass(className)
	_G[className]={}
	local obj = _G[className]
	self.__index=self
	setmetatable(obj,self)
	obj.base=self--新加一个Base字段
	return obj
end

不过这时候想要实现就要认真考虑了,不要贸然地使用**:**

接着我们总结一下,因为这部分比较重要

Object = {}

--new 实例化一张空表

function Object:new() 
    local obj = {}
     self.__index = self
    setmetatable(obj, self)
    return obj
end

--继承

function Object:subClass(className)
    _G[className] = {}
    local obj = _G[className]
    obj.base=self
    self.__index = self
    setmetatable(obj, self)
end

Object:subClass("GameObject")

function GameObject:new() 
    local obj = {}
    obj.posX = 0
    obj.posY = 0
    setmetatable(obj, self)
    self.__index = self
    return obj
end

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)

--多态
GameObject:subClass("Player") --继承自Gameobject
function Player:Move()
	
    self.base.Move(self) --子类调用父类方法,并且参数使用自己的
end
local obj3=Player:new()
obj3:Move()

自带库

时间

print(os.time())--得到系统时间

local nowTime=os.date("*t")--nowtime是一个表,存了很多时间相关,可以通过pairs遍历查看

print(nowTime.hour)

数学运算

--绝对值
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(1,2))

--小数分离
print(math.modf(1.2)) 
--幂运算 
print(math.pow(2, 5))
--随机数
--先设置随机种子  
math.randomseed(os.time())
print(math.random(100))  

路径

--用lua脚本加载路径
print(package.path)

垃圾回收

在lua中,释放内存的方式就是变nil
有自动定时GC的方法
但是尽量不要使用自动垃圾回收

介绍一下collectgarbage,用于手动触发GC

相关推荐

  1. <span style='color:red;'>lua</span><span style='color:red;'>语法</span>

    lua语法

    2024-04-28 20:54:04      33 阅读
  2. <span style='color:red;'>Lua</span><span style='color:red;'>语法</span>

    Lua语法

    2024-04-28 20:54:04      29 阅读
  3. <span style='color:red;'>Lua</span><span style='color:red;'>语法</span>

    Lua语法

    2024-04-28 20:54:04      14 阅读
  4. Lua语言

    2024-04-28 20:54:04       45 阅读
  5. lua基本语法使用

    2024-04-28 20:54:04       36 阅读
  6. LUA语法复习总结

    2024-04-28 20:54:04       18 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-28 20:54:04       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-28 20:54:04       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-28 20:54:04       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-28 20:54:04       20 阅读

热门阅读

  1. Excel常用函数

    2024-04-28 20:54:04       12 阅读
  2. 发布自己的npm包

    2024-04-28 20:54:04       14 阅读
  3. 【VUE】moment.js 时间日期格式化工具

    2024-04-28 20:54:04       13 阅读
  4. vue3 ts table合计样式更改

    2024-04-28 20:54:04       12 阅读
  5. MySQL详细步骤及案列

    2024-04-28 20:54:04       14 阅读
  6. maya 设置半径 获取时长,设置时长

    2024-04-28 20:54:04       14 阅读
  7. react写一个从下往上划出的弹框弹窗组件

    2024-04-28 20:54:04       10 阅读
  8. redis 键常用命令

    2024-04-28 20:54:04       14 阅读