lua语法

  |   0 评论   |   0 浏览

lua语法

1.lua数据类型

lua 脚本输出乱码,将lua脚本改为UTF-8编码,并且需要DOS下修改代码页:CHCP 65001 即可。

image-20231218210209855

基本语法

注释

print("script lua win")

-- 单行注释

--[[

多行注释

]]--

标识符

类似于:java当中 变量、属性名、方法名。

以字母(a-z,A-Z)、下划线 开头,后面加上0个或多个 字母、下划线、数字。

不要用下划线+大写字母。

保留字。

总结一点:按照正常思维命名即可。

全局变量

print(a) -- nil
a=1
print(a)
a=nil --销毁a
print(a)
  • nil

没有任何有效值,就是一个 nil。 可以用于删除

print("---delete---")
-- 定义一个table
myTab = {key1="value1",key2="value2"}
for k,v in pairs(myTab) do
	print(k.."_"..v)
end

print("---after delete---")
myTab.key1=nil
for k,v in pairs(myTab) do
	print(k.."_"..v)
end

print("---判断是否为nil")
print(x) -- nil
print((type(x)==nil)) -- false
print(type(x)=='nil') -- true

image-20231215163327032

  • boolean

lua会将false(false\nil) 看做是false, 其他的都看做是 true(其他都为true,包括0)

print("---boolean---")

print(type(true))  -- boolean
print(type(false)) -- boolean
print(type(nil))  -- nil

if false or nil then
	print("nil被当为true")
else
	print("nil为false") -- false
end

print("---测试0---")
if 0 then 
	print("0 是true") -- true
else 
	print("0 是false")
end
  • number

双精度(8个字节)。

print("---------测试number-------------")
a = 10
print(type(a))
  • String

字符串用单引号或双引号来表示。

print("双引号字符串")

print("单引号字符串")

用 [[可以换行的字符串 ]]

i = [[

我是中国人,

我爱我的祖国!

]]

print(i)

字符串和数字进行数学运算,优先将 字符串 转 成 数字。

print("1" + 2) -- 3

print("1" + "2") -- 3

print("1+2") -- 1+2

-- 非数字的字符串和数字进行计算,则会报错-- lua: string.lua:1: attempt to perform arithmetic on a string value
print("error"+1)

字符串连接

-- error1
print("error"..1)

计算字符串长度(#字符串)

testLenth = "abcde"

print("testLenth的长度为:"..#testLenth)
  • table

类比成java当中:数组,map,链表,队列等。

table的key的索引,从1开始。

print("---------测试 table-------------")
tab1 = {}

tab2 = {"a","b","c"}

tab3 = {key1="value1", key2 = "value2"}
print("tab3-:")
for k,v in pairs(tab3) do
 print(k.."="..v)
end 
print("tab3:")

tab1["a_key"]="a_value"
for k,v in pairs(tab1) do
 print(k.."="..v)
end 

for k,v in pairs(tab2) do
 print(k.."="..v)
end 
-- table的key的索引,从1开始。
-- 1=a
-- 2=b
-- 3=c


-- 删除table中的元素
print("tab3-:")
tab3["key2"] = nil
for k,v in pairs(tab3) do
 print(k.."="..v)
end 
print("tab3:")
  • function

阶乘:

function factorial(n)
 if n == 0 then
 return 1
 else
 return n * factorial(n - 1)
 end
end
testFac = factorial
print("6的阶乘结果:"..testFac(6))

匿名函数

print("------------匿名function-------------")
-- 定义函数
function testPrint(tab, func)
 for k,v in pairs(tab) do
 print(func(k,v))
 end
end

-- 定义数组调用函数
tab1 = {"a","b","c"}
testPrint(tab1,
 function(k,v)
 return k.."="..v
 end
)

2.变量赋值

a = 变量值。

print("---变量赋值---")
a,b=1,2
a = 1+2
print(a,b) -- 3  2

常用:x , y = y, x

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

变量个数 > 值的个数:按照变量的个数 补足 nil。

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

变量个数<值的个数:多余的值会被忽略。

a,b = 1,2
function var() 
 a = nil
 b = 3
 local c = 4
 print(c) -- 4
 return a,b
end

a,b = var()
print(a,b,c) -- nil     3       nil

多变量赋值:还可以用于函数的返回, 参数值互换。

a,b = func();

需要赋值给变量,如果能用局部变量,尽量用局部变量。

3.索引

lua索引中的下标是从1开始的

对table中元素的访问。

tab["key"]

tab.key

print("-----------索引--------------")
tab = {key1 = "中国",key2 = "美国"}
print(tab["key1"]) -- 中国
print(tab.key2) --美国

4.循环

用途:做一些有规律的重复操作。
循环体:一组被重复执行的语句。循环条件:判断能否继续循环。

while循环

while(循环条件)
do
业务代码;
对循环条件的控制;
end
a = 1
while(a<5)
do
 print(a)
 a = a+1
end

for循环

数值for循环:
for var=exp1,exp2,exp3 do
循环体
end

var的值,从exp1一直到exp2,步长是exp3(是可选的,默认是1)

print("----for----")
for i=1,10,2 do
 print(i) -- 1 3 5 7 9
end

exp1,exp2,exp3 只在循环开始前计算一次。

print("----for----")
for i=1,test(2) do
 print(i) -- 1 2 3 4
end

泛型for循环:

是通过迭代器进行的。

a = {"one","two","three"}
for k,v in pairs(a) do
 print(v)
end

repeat until

repeat
循环体
until(条件)
先执行循环体,直到满足条件。如果条件为false,继续执行循环体,如果条件为true,则跳出循
环。
a = 1
repeat 
 a = a+1
 print(a)
until(a>5)
print(a)--6

5.流程控制

if()

print("-----------if-------------")
a = 1
if(a == 1) then
 print(a.."是1")
end

0 是 true。

6.函数

函数定义

print()

功能:1。完成指定的任务。2。计算并返回值(可以返回多个值)。

函数的范围(local ,缺省) function 函数名称(参数列表)

函数体;

return 结果

end

定义一个函数:实现求两个数的最大值。

print("---------------函数定义:求最大值---------------")
function testMax(num1,num2)
 if (num1 > num2) then
 result = num1;
 else
 result = num2;
 end
 return result;
end
print("15,20中的最大值是:"..testMax(15,20)) -- 20

函数可以作为参数进行传递。

例子:自定义打印函数。

print("---------------函数定义:自定义打印函数---------------")
myPrint = function(p)
 print("重新的打印函数:",p)
end;
myPrint("test");
function add(num1,num2,myPrintParam)
 result = num1 + num2;
 myPrintParam(result);
end
add(2,3,myPrint)

image-20231218215001500

多值返回

print("---------------多值返回---------------")
startIndex,endIndex = string.find("www.llp.com","llp")
print(startIndex , endIndex) -- 5       7

例子:找出一个数组中,最大的值,以及它的索引。

print("---------------找出数组中,最大的值,以及索引---------------")
function testMax(a)
 local iIndex = 1;
 local iValue = a[iIndex];
 for i,v in pairs(a) do
 if v > iValue then
 iIndex = i;
 iValue = v;
 end
 end
 return '最大值的索引:'..iIndex , '最大值是:'..iValue
end
print(testMax({1,4,8,2,7,10,6,3})) -- 最大值的索引:6 最大值是:10

可变参数

例子:求和

print("---------------可变参数:求和---------------")
function add1(...)
 local result = 0;
 for i,v in pairs(...) do
 result = result + v;
 end
 return result;
end
print(add1({1,2,3,4,5})) -- 这里传入的是一个固定的数组

这个参数只有一个,不是可变的。

function add1(...)
 local result = 0;
 for i,v in pairs({...}) do
 result = result + v;
 end
 return result;
end
print(add1(1,2,3,4))  -- 这样才是可变的

如何确定可变参数的数量,用#

例子:求平均数

print("---------------可变参数:求平均数---------------")
function average1(...)
 local result = 0;
 arg = {...}
 for i,v in pairs(arg) do
 result = result + v;
 end
 num = #arg
 print("参数的个数: "..num) -- 6
 return result / num;
end
print(average1(1,2,3,4,5,6)) -- 3.5

用select获取可变参数的数量

function average1(...)
 local result = 0;
 arg = {...}
 for i,v in pairs(arg) do
 result = result + v;
 end
 num = select("#",...)
 print("个数是:"..num) -- 5
 return result / num;
end
print(average1(1,2,3,4,5)) -- 3

函数的参数中,有固定参数,也有可变参数。固定参数写前面。

例子:固定参数和可变参数结合。用某个格式,输出可变参数。

print("---------------固定参数和可变参数结合---------------")
function fmtPrint(fmt,...)
 io.write(string.format(fmt,...))
end
fmtPrint("%d\t%d\n%d",2,3,4)

image-20231219093326957

选取可变参数的值

print("---------------选取可变参数中的值---------------")
function testSelect(...)
 a,b,c = select(3,...)
 print(a,b,c) -- 3 4 5
end
testSelect(1,2,3,4,5)

7.运算符

  • 算术运算符
+ 加
- 减
* 乘
/ 除
% 取余
^ 乘幂
- 负号
  • 关系运算符
== 等于。
~=不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
  • 逻辑运算符
and 
or
not
  • 其他运算符
.. 连接符
# 计算字符串或者 表 的长度。

8.数组

数组:相同元素的集合。

索引用整数表示:从1开始。

print("------多维数组--------")
testArray2 = {}
for i=1,3,1 do
 testArray2[i]={}
 for j=1,2,1 do
 testArray2[i][j] = i*j
 end
end

for i=1,3 do
 for j=1,2 do
 print(testArray2[i][j])
 end
 print("------")
end

9.迭代器

泛型 for 迭代器

a = {"a","b","c"}
for k,v in pairs(a)
do
 print(k,v)
end
a = {"a",key2="b","c"}
for k,v in ipairs(a)
do
 print(k,v)
end

image-20231219101110690

pairs会遍历所有key和值。

ipairs:只会从1开始,步长是1,中间不是数字作为key的元素会被忽略,一直到第一个不连续的数

字索引为止(不含)。适合遍历数组。

for迭代器的结构:

for 变量列表 in 迭代函数 ,状态常量,控制变量

do

循环体

end

print("-------迭代器的定义例子--------")
-- 求平方 1-9的平方
function square(iteratorMaxCount,currentNumber)
 if currentNumber < iteratorMaxCount then
 currentNumber = currentNumber +1
 return currentNumber,currentNumber*currentNumber
 end
end

for i,n in square ,9,0
do
print(i,n)
end

image-20231219102741398

10.table

a = {key1="a",key2="b"}

不能用nil做索引。

-- table
-- 初始化
myTable = {}
myTable[1] = "1"
-- 删除
myTable = nil
print("--------------------")
myTab = {}
print("myTab的类型是:"..type(myTab))
myTab[1]="1号元素"
myTab["a"]="a元素"
print("myTab[1]的元素是:"..myTab[1])
print("myTab['a']的元素是:"..myTab["a"])
-- 将myTab赋值
newMyTab = myTab;
print("newMyTab[1]的元素是:"..newMyTab[1])
print("newMyTab['a']的元素是:"..newMyTab["a"])
-- 修改元素
newMyTab["a"]="新值"
print("myTab['a']的元素是:"..myTab["a"])
print("newMyTab['a']的元素是:"..newMyTab["a"])
-- 置为nil
myTab = nil
print(myTab)
print("newMyTab[1]的元素是:"..newMyTab[1])
print("newMyTab['a']的元素是:"..newMyTab["a"])
myTab的类型是:table
myTab[1]的元素是:1号元素
myTab['a']的元素是:a元素
newMyTab[1]的元素是:1号元素
newMyTab['a']的元素是:a元素
myTab['a']的元素是:新值
newMyTab['a']的元素是:新值
nil
newMyTab[1]的元素是:1号元素
newMyTab['a']的元素是:新值

11.模块

模块的定义

从lua5.1开始,引入了模块机制,把一些公用的代码放到文件中,通过api的方式,让其他程序调用,这个文件,就是一个模块。

类似于java中的jar包。

lua中的模块,其实是一个table(由 变量、函数等已知的 lua元素组成)。最后在模块的结尾,需要返回一个table。

如何编写模块

文件名:module.lua

-- 模块 :module.lua
module = {}
module.constant = "模块中的常量"
function module.func1()
 print("这是函数1")
end
-- 这块,注意 module不能写。私有函数外部是无法访问的,需要通过其他公共的函数进行调用
local function func2()
 print("这是私有函数2")
end
function module.func3()
 func2()
end
-- 返回表 ,一定要注意返回table
return module

require函数

前面我们定义好了一个模块,那么模块应该如何调用呢,引入模块有如下两种方式:

require("模块名")

require "模块名"

-- 调用模块
require("module")
print(module.constant)
module.func3()

image-20231219110641747

12.元素

元表的定义

允许我们改变table的行为。

setmetatable(普通表,元表)

-- 元表
a = {"a","b","c"} -- 普通表
b = {} --元表
c = setmetatable(a,b)
print("------------------------")
f = {}
print("f:",f)
d = setmetatable({"c","d"},f)
print(d[1]) 
e = getmetatable(d)
print("e:",e)

image-20231219124517662

index元方法

__index (两个下划线)

定义普通表 p。

给普通表p,设置元表y,而元表y中有__index,__index=一个表 i,i中有 我们访问的那个不存在的key。

__index=表

print("-------------测试__index---------------")
-- 普通表
tab1 = {"a","b","c"}
print(tab1[5]) -- nil
-- 普通表,有一个元素 5="e"
newTab = {}
newTab[5] = "e"
metaTab1 = {__index=newTab}
setmetatable(tab1, metaTab1)
print(tab1[5]) -- e

--index=函数(表,key)
-- 普通表
tab1 = {"a","b","c"}
print(tab1[5]) -- nil
print("原始的tab1:",tab1) -- 原始的tab1:     table: 00CF92E0
metaTab1 = {
 __index=function(tab, key )
 print("参数当中的tab:",tab) -- 参数当中的tab:  table: 00CF92E0
 print("参数当中的key:",key) -- 5
 if(key == 5) then
 return "index--5"
 end
 end
}
setmetatable(tab1, metaTab1)
print(tab1[5]) --  index--5

请求表中key的值:

先在普通表中找,有返回,没有,看元表。

如果元表有__index, 且 __index中有对应的key。

如果没有,继续找__index的function。

newindex元方法

对表进行更新时调用

函数用法

print("-----------newindex--------------")
mytab2 = {"a","b"}
metatab2 = {
 __newindex = function(tab, key ,value)
 print("被调用") 
 -- tab[key] = value
 rawset(tab,key,value) --给table的key赋value的值
 end
}
setmetatable(mytab2,metatab2)
mytab2[3]="c"
print(mytab2[3]) -- c

image-20231219130359264

mytab2 = {"a","b"}
mytab21 = {}
metatab2 = {
 __newindex = mytab21
}
setmetatable(mytab2,metatab2)
mytab2[3]="c"
print(mytab2[3]) -- nil
print(mytab2[3]) -- nil

为表添加操作符

加法操作

print("-------------操作符------------")
tab3 = {"1","2"}
tab4 = {"a","b","c"}
metatab3 = {
 __add = function(tab1,tab2)
 local m = #tab1
 for k,v in pairs(tab2)
 do
 m = m+1
 tab1[m] = v
 end
 return tab1
 end
}
setmetatable(tab3,metatab3)
v = tab3 + tab4
print(v)
for k,v in pairs(v)
do
 print(k,v)
end

__add:+

__sub: -

_mul:*

__div: /

__mod: %

__concat: ..

__eq:==

__lt: <

_le: <=

call元方法

lua中,当表被当成函数调用时,会触发。

print("-----------call-------------")
tab_a1 = {"a","b"}
print("tab_a1原始值:",tab_a1)
tab_a2 = {"1","2"}
metatab_a = {
 __call = function(tab, ...)
local a = {...} 
for k,v in pairs(a) do 
    print(v) 
	end 
end
}
setmetatable(tab_a1,metatab_a)
result = tab_a1(6,7,8)

image-20231219160701242

tostring

用于修改表的输出行为。类似于java中的toString()。

print("-----------call-------------")
tab_a1 = {"a","b","c","d"}
print("tab_a1原始值:",tab_a1)
tab_a2 = {"1","2"}
metatab_a = {
 __call = function(tab, ...)
 local a = {...}
 for k,v in pairs(a) do
 	print(v)
 	end
 end,
 __tostring = function(tab)
 local str = ""
 for k,v in pairs(tab) do
 str = str..v..","
    end
 return str
 end
}
setmetatable(tab_a1,metatab_a)
-- result = tab_a1(6,7,8)
print(tab_a1)

ps:每个元方法之间 用 ,

13.协同程序

类似于 多线程的概念。

协程和线程的区别:

一个多线程的程序,可以同时运行多个线程。而协程呢,在某个时刻,只有一个协程在运行。

线程由cpu调度,协程由代码调度。

创建协程,并运行:

-- 定义协程
testAdd = coroutine.create(
 function(a,b)
 print(a+b) --3
 end
)

-- 启动协程
-- 原来暂停-》执行,原来执行-》暂停
coroutine.resume(testAdd, 1,2)

wrap,这种方式运行协程只需要调用就可以执行

co = coroutine.wrap(
 function(a)
 print("参数值是:"..a)
 end
)
co(2)

启动、停止

testAdd = coroutine.create(
 function(a,b)
 print("执行--子方法",a+b)
 coroutine.yield();
 print("执行--子方法",a-b)
 end
)
coroutine.resume(testAdd, 1,7) -- 8
print("执行主方法")
coroutine.resume(testAdd) -- -6

image-20231219162739820

返回值

testAdd = coroutine.create(
 function(a,b)
 print("协程执行",a+b)
 coroutine.yield()
 return a+b,a-b
 end
)
r1,r2,r3 = coroutine.resume(testAdd, 1,7)
print("返回值:",r1,r2,r3)
r1,r2,r3 = coroutine.resume(testAdd, 1,7)
print("重新执行,返回值:",r1,r2,r3)

image-20231219163316441

协程状态

testAdd = coroutine.create(
 function(a,b)
 print("运行中 协程状态:",coroutine.status(testAdd))
 coroutine.yield() -- 放弃协程
 return a+b,a-b
 end
)
print("刚定义好的协程状态:",coroutine.status(testAdd))
r1 = coroutine.resume(testAdd,1,4)
print("启动协程结果:",r1)
print("最终的 协程状态:",coroutine.status(testAdd))
print("yield后 协程状态:",coroutine.status(testAdd))
r1 = coroutine.resume(testAdd,1,4)
print("二启动协程结果:",r1)
print("二最终的 协程状态:",coroutine.status(testAdd))
r1 = coroutine.resume(testAdd,1,4)
print("三启动协程结果:",r1)

结果:

刚定义好的协程状态:     suspended
运行中协程状态:       running
启动协程结果:  		 true
最终的协程状态:       suspended
yield后协程状态:     suspended
二启动协程结果:        true
二最终的协程状态:     dead
三启动协程结果:        false

协程协作

协程唯一标识

-- 协程内外部协作的例子
function foo(a)
 print("foo 参数:",a)
 return coroutine.yield(a*2)
end
co = coroutine.create(
 function(a,b)
 print("第一次启动协程,参数:",a,b)
 local r = foo(a+1)
 print("第二次启动协程,参数",r)
 local x,y = coroutine.yield(a+b,a-b)
 print("第三次启动协程,参数",x,y)
 return b,"协程结束啦"
 end
)
print("主程序:",coroutine.resume(co,1,5))
print("----分隔符---")
print("主程序:",coroutine.resume(co,"r"))
print("----分隔符---")
print("主程序:",coroutine.resume(co,"x","y"))
print("----分隔符---")
print("主程序:",coroutine.resume(co))

image-20231219170205916

协程内部和外部协作的例子:

第一次resume,传入的参数是 function的参数。

第一次yield的参数,是第一次resume的返回值。

第二次resume的参数,是第一次yield的 返回值。

生产者消费者问题

思路:

  1. 生产者生产完 产品,(自己停下来),等待消费者消费。
  2. 消费者消费完产品,(自己停下来),等待生产者生产。
-- 生产者和消费者
function productor()
 -- 定义生产的商品,用数字来替代
 local i = 0
 while i<100
 do
 i = i+1
 print("生产了:",i)
 -- 通过协程实现
 coroutine.yield(i)
 end
end

function consumer()
 while true
 do
 -- 从生产者获取产品
 local status,result = coroutine.resume(po)
 print("消费了:",result)
 if (result == 99) then
 break
 end
 end
end
-- 程序开始
po = coroutine.create(productor)
consumer()

14.错误处理

语法错误:

-- 错误处理
a==10
for a = 1,10
print(a)
end

程序无法运行。

运行错误:

错误处理 assert和error

assert:

第一个参数为true,不输出第二个参数。

第一个参数为false,输出第二个参数。

function add(a,b)
 assert(b,"b是nil")
end
add(1)

error

function add(a,b)
 if(b==2) then
 error("报error了")
 end
 print("正常执行")
end
add(1,2)

当error或assert,触发错误时,程序退出。

错误处理pcall

pcall(要执行的函数,函数需要的参数)

如果函数执行没问题,返回true

如果函数执行有问题,返回false。

function add(a,b)
 c = a+b
 print("正常执行")
end
if pcall(add,1) then
 print("add 正常")
else
 print("add 错误")
end
print("主程序")

--运行结果
add 错误
主程序

image-20231219171946830

错误处理xpcall

function testXpcall()
 c = 1+nil
end
function testErrorHandle(error)
 print("我来处理错误",error)
end
xpcall(testXpcall,testErrorHandle)

image-20231219171914201

15.面相对象

对象:属性、方法。

table,function。

student = {name = "张三",age = 18,
gotoSchool = function(name)
 print(name.."上学")
end}
--[[
下面两种方式也是支持的
student.gotoSchool = function(name)
 print(name.."上学")
end
function student.gotoSchool(name)
 print(name.."上学")
end
]]--
print("学生姓名:"..student.name..",年龄是:"..student.age)
student.gotoSchool(student.name)

技巧冒号

1。类比:一个类,实例化多个对象。

Student = {name="默认名称"}
function Student:new()
	s = {}
	setmetatable(s,{__index = self})
	return s
end

s1 = Student:new()
s2 = Student:new()
s1.name="张三"
s2.name="李四"
print(s1.name)
print(s2.name)

image-20231219173247964


标题:lua语法
作者:llp
地址:https://llinp.cn/articles/2023/12/18/1702887098277.html