lua语法
1.lua数据类型
lua 脚本输出乱码,将lua脚本改为UTF-8编码,并且需要DOS下修改代码页:CHCP 65001 即可。
基本语法
注释
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) doprint(k.."_"..v)
endprint("---after delete---")
myTab.key1=nil
for k,v in pairs(myTab) doprint(k.."_"..v)
endprint("---判断是否为nil")
print(x) -- nil
print((type(x)==nil)) -- false
print(type(x)=='nil') -- true
- boolean
lua会将false(false\nil) 看做是false, 其他的都看做是 true(其他都为true,包括0)
print("---boolean---")print(type(true)) -- boolean
print(type(false)) -- boolean
print(type(nil)) -- nilif false or nil thenprint("nil被当为true")
elseprint("nil为false") -- false
endprint("---测试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) -- 3print("1" + "2") -- 3print("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) doprint(k.."="..v)
end
print("tab3:")tab1["a_key"]="a_value"
for k,v in pairs(tab1) doprint(k.."="..v)
end for k,v in pairs(tab2) doprint(k.."="..v)
end
-- table的key的索引,从1开始。
-- 1=a
-- 2=b
-- 3=c-- 删除table中的元素
print("tab3-:")
tab3["key2"] = nil
for k,v in pairs(tab3) doprint(k.."="..v)
end
print("tab3:")
- function
阶乘:
function factorial(n)if n == 0 thenreturn 1elsereturn n * factorial(n - 1)end
end
testFac = factorial
print("6的阶乘结果:"..testFac(6))
匿名函数
print("------------匿名function-------------")
-- 定义函数
function testPrint(tab, func)for k,v in pairs(tab) doprint(func(k,v))end
end-- 定义数组调用函数
tab1 = {"a","b","c"}
testPrint(tab1,function(k,v)return k.."="..vend
)
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 = nilb = 3local c = 4print(c) -- 4return a,b
enda,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)
doprint(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 doprint(i) -- 1 3 5 7 9
end
exp1,exp2,exp3 只在循环开始前计算一次。
print("----for----")
for i=1,test(2) doprint(i) -- 1 2 3 4
end
泛型for循环:
是通过迭代器进行的。
a = {"one","two","three"}
for k,v in pairs(a) doprint(v)
end
repeat until
repeat
循环体
until(条件)
先执行循环体,直到满足条件。如果条件为false,继续执行循环体,如果条件为true,则跳出循
环。
a = 1
repeat a = a+1print(a)
until(a>5)
print(a)--6
5.流程控制
if()
print("-----------if-------------")
a = 1
if(a == 1) thenprint(a.."是1")
end
0 是 true。
6.函数
函数定义
print()
功能:1。完成指定的任务。2。计算并返回值(可以返回多个值)。
函数的范围(local ,缺省) function 函数名称(参数列表)函数体;return 结果end
定义一个函数:实现求两个数的最大值。
print("---------------函数定义:求最大值---------------")
function testMax(num1,num2)if (num1 > num2) thenresult = num1;elseresult = num2;endreturn 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)
多值返回
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) doif v > iValue theniIndex = i;iValue = v;endendreturn '最大值的索引:'..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(...) doresult = result + v;endreturn result;
end
print(add1({1,2,3,4,5})) -- 这里传入的是一个固定的数组
这个参数只有一个,不是可变的。
function add1(...)local result = 0;for i,v in pairs({...}) doresult = result + v;endreturn result;
end
print(add1(1,2,3,4)) -- 这样才是可变的
如何确定可变参数的数量,用#
例子:求平均数
print("---------------可变参数:求平均数---------------")
function average1(...)local result = 0;arg = {...}for i,v in pairs(arg) doresult = result + v;endnum = #argprint("参数的个数: "..num) -- 6return 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) doresult = result + v;endnum = select("#",...)print("个数是:"..num) -- 5return 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)
选取可变参数的值
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 dotestArray2[i]={}for j=1,2,1 dotestArray2[i][j] = i*jend
endfor i=1,3 dofor j=1,2 doprint(testArray2[i][j])endprint("------")
end
9.迭代器
泛型 for 迭代器
a = {"a","b","c"}
for k,v in pairs(a)
doprint(k,v)
end
a = {"a",key2="b","c"}
for k,v in ipairs(a)
doprint(k,v)
end
pairs会遍历所有key和值。
ipairs:只会从1开始,步长是1,中间不是数字作为key的元素会被忽略,一直到第一个不连续的数
字索引为止(不含)。适合遍历数组。
for迭代器的结构:
for 变量列表 in 迭代函数 ,状态常量,控制变量
do
循环体
end
print("-------迭代器的定义例子--------")
-- 求平方 1-9的平方
function square(iteratorMaxCount,currentNumber)if currentNumber < iteratorMaxCount thencurrentNumber = currentNumber +1return currentNumber,currentNumber*currentNumberend
endfor i,n in square ,9,0
do
print(i,n)
end
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()
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)
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: 00CF92E0print("参数当中的key:",key) -- 5if(key == 5) thenreturn "index--5"endend
}
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] = valuerawset(tab,key,value) --给table的key赋value的值end
}
setmetatable(mytab2,metatab2)
mytab2[3]="c"
print(mytab2[3]) -- c
表
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 = #tab1for k,v in pairs(tab2)dom = m+1tab1[m] = vendreturn tab1end
}
setmetatable(tab3,metatab3)
v = tab3 + tab4
print(v)
for k,v in pairs(v)
doprint(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)
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) doprint(v)endend,__tostring = function(tab)local str = ""for k,v in pairs(tab) dostr = str..v..","endreturn strend
}
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) --3end
)-- 启动协程
-- 原来暂停-》执行,原来执行-》暂停
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
返回值
testAdd = coroutine.create(function(a,b)print("协程执行",a+b)coroutine.yield()return a+b,a-bend
)
r1,r2,r3 = coroutine.resume(testAdd, 1,7)
print("返回值:",r1,r2,r3)
r1,r2,r3 = coroutine.resume(testAdd, 1,7)
print("重新执行,返回值:",r1,r2,r3)
协程状态
testAdd = coroutine.create(function(a,b)print("运行中 协程状态:",coroutine.status(testAdd))coroutine.yield() -- 放弃协程return a+b,a-bend
)
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))
协程内部和外部协作的例子:
第一次resume,传入的参数是 function的参数。
第一次yield的参数,是第一次resume的返回值。
第二次resume的参数,是第一次yield的 返回值。
生产者消费者问题
思路:
- 生产者生产完 产品,(自己停下来),等待消费者消费。
- 消费者消费完产品,(自己停下来),等待生产者生产。
-- 生产者和消费者
function productor()-- 定义生产的商品,用数字来替代local i = 0while i<100doi = i+1print("生产了:",i)-- 通过协程实现coroutine.yield(i)end
endfunction consumer()while truedo-- 从生产者获取产品local status,result = coroutine.resume(po)print("消费了:",result)if (result == 99) thenbreakendend
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) thenerror("报error了")endprint("正常执行")
end
add(1,2)
当error或assert,触发错误时,程序退出。
错误处理pcall
pcall(要执行的函数,函数需要的参数)
如果函数执行没问题,返回true
如果函数执行有问题,返回false。
function add(a,b)c = a+bprint("正常执行")
end
if pcall(add,1) thenprint("add 正常")
elseprint("add 错误")
end
print("主程序")--运行结果
add 错误
主程序
错误处理xpcall
function testXpcall()c = 1+nil
end
function testErrorHandle(error)print("我来处理错误",error)
end
xpcall(testXpcall,testErrorHandle)
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
ends1 = Student:new()
s2 = Student:new()
s1.name="张三"
s2.name="李四"
print(s1.name)
print(s2.name)