lua基础知识套装
lua语言学习
定义
是一种轻量小巧的脚本语言,用标准C语言编写并以源码形式开放
目的
为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能
特点
- 轻量级:它用标准C语言编写并以源码形式开放、编译后仅仅一百k,可以方便嵌入别的程序里。
- 可扩展性:lua提供了非常易于使用的扩展接口和机制:由宿主语言(C/C++)提供这些功能,lua可以使用它们,就像本来就是内置的功能一样。(这里不太明白)
- 其他特性
- 支持面向过程和函数式编程
- 自动内存管理:只提供一种通用类型的表,用它可以实现数组、哈希表、集合、对象
- 语言内置模式匹配:闭包;函数也可以看做一个值;提供多线程(协同进程、并非操作系统所支持的线程)支持;
- 通过闭包和table可以很方便地支持面向对象编程所需要的一些关键机制,比如数据抽象、虚函数、继承和重载等。
应用场景
- 游戏开发
- 独立应用脚本
- Web应用脚本
- 扩展和数据库插件:MySQL Proxy和MySQL WorkBench
- 安全系统,如入侵检测系统
window的安装方式
- 下载教程
https://wangyi.blog.csdn.net/article/details/94561551?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-7.control
- 下载比较新的lua
https://blog.csdn.net/qq_39097425/article/details/103498944
基础知识
注释
- 单行注释
-- 注释
- 多行注释
--[[
多行注释
多行注释
]]
-
全局变量:在默认情况下,变量总是认为是全局的。全局变量不需要声明,给一个变量赋值后创建了这个全局变量,访问一个没有初始化的全局变量也不会出错,只不过得到的结果是:nil
b = nil print(b -- nil
数据类型
-
Lua是动态类型语言,变量不要类型定义,只需要为变量赋值。值可以存储在变量中,作为参数传递或结果返回
-
Lua中有8个数据类型
数据类型 描述 nil 值为nil属于该类,表示一个无效值(在条件表达式中相当于table) boolean 布尔类型:false和true number 表示双精度类型的浮点数 string 字符串由一对双引号或者单引号表示 function 由C或Lua编写的函数 userdata 表示任意存储在变量中的C数据结构 thread 表示执行的独立线路,用于执行协同程序 table Lua中的表,其实是一个“关联数组”,数组的索引可以是数字、字符串或表类型。在Lua里,table的创建是通过构造表达式来完成,最简单构造表达式{}用来创建一个空表 -
a = "hello world" print("字符串",a) a = 10.4 *3 print("number",a) a = print print("函数",a) a = true print("布尔类型",a) a = nil print("nil",nil) -- table -- 创建一个空的table local tab1 = {} -- 直接初始化一个table,表示数组 local tab2 = {"apple","peer","orange","grape"} print("table表示数组:",tab2) -- 表示map:key-value local tab3 = {} tab3[1] = "a" tab3[2] = "b" print("table表示map:",tab3) -- 函数 local function factorial(n) if n == 0 then return 1 else return n*factorial(n-1) end end print("函数:",factorial) print("斐波那契数列值:",factorial(3)) -- 协程 local coco = coroutine.create(function (a,b) print("协程 resume args:"..a..","..b) local yreturn = coroutine.yield() print("协程yreturn:"..yreturn) end) coroutine.resume(coco,0,1) coroutine.resume(coco,21)
变量
-
变量类型:全局变量、局部变量、表中的域
-
注意:Lua中的变量全是全局变量,哪怕是语句块或是函数里,除非用local显式声明为局部变量。并且如果局部变量的作用域没有在某个函数块中,也可以当作是全局变量。也就是说局部变量的作用域从声明位置开始到所在语句块结束。
-
实例
-
a = 5 local b = 6 -- 这个也可以说是全局变量,因为它的作用域可以到程序运行结束 function joke() c = 7 local d = 8 f = 111 -- 在语句块中 end joke() print(a,b,c,d,f) do local a = 9 b = 10 print(a,b) end print(a,b) --[[ 输出结果 5 6 7 nil 111 9 10 5 10 ]]--
-
-
赋值语句
-
Lua可以对多个变量同时赋值,变量列表和值列表的各个元素逗号分开,赋值语句右边的值会依次赋给左边的变量
-
a,b = 10,2*x
-
当变量个数和值的个数不一致时,lua会一直以变量个数为基础采取以下策略
- 变量个数大于值的个数 按变量个数补足nil
- 变量个数小于值的个数,多余的值回被忽略
-
-
索引
- t[i] 跟其它语言一样的方式
- t.i 当索引为字符串类型时一种简化写法
- gettable_event(t,i) 采用索引访问本质上是一个类似这样的函数调用
-
Lua循环
- 循环类型
循环类型 | 描述 |
---|---|
while | 在条件为true的时,让程序重复地执行某些语句。执行语句前会先检查条件是否为true |
for | 重复执行指定语句,重复次数可在for语句地控制 |
repeat...until | 重复执行循环,直到指定地条件为真时止 |
- 循环控制语句
控制语句 | 描述 |
---|---|
break语句 | 退出当前循环或语句,并开始脚本执行紧接者地语句 |
goto语句 | 将程序地控制点转移到一个标签处 |
- 示例i
-- while
a = 1
while (a<4 )do
print(a)
a = a + 1
end
-- for
for i=1,6,1 do
-- body
print(i)
end
for i=8,0,-1 do
-- body
print(i)
end
days = {"Sun","Mon","Tues","Wed","Thur","Fri","Sat"}
for i,v in pairs(days) do
-- body
print(i,v)
end
-- repeat until
c = 10
repeat
print(c)
c = c + 1
until (c>19) -- 为真的时候退出循环l
控制语句
- 控制结构的条件表达式结果可以是任何值,lua认为false和nil为假,true和非nil为真,并且0也是真
if(0) then
print("0 is true")
end
-- 非空
a=1
if(a) then
print("a = ",a)
end
a = 1
if(a==1)then
print("a is 1")
a=2
elseif(a==2) then
print("a is 2")
a = 3
elseif (a==3) then
print("a is 3")
else
print("a is 1、2、3")
end
函数
-
函数定义
-
optional_function_scope function function_name( argument1, argument2, argument3..., argumentn) function_body return result_params_comma_separated end
- optional_function_scope: 该参数是可选的制定函数是全局函数还是局部函数,未设置该参数默认为全局函数,如果你需要设置函数为局部函数需要使用关键字 local。
- function_name: 指定函数名称。
- argument1, argument2, argument3..., argumentn: 函数参数,多个参数以逗号隔开,函数也可以不带参数。
- function_body: 函数体,函数中需要执行的代码语句块。
- result_params_comma_separated: 函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开。
可变参数
-
Lua 函数可以接受可变数目的参数,和 C 语言类似,在函数参数列表中使用三点 ... 表示函数有可变的参数。
-
处理方法如下:
-
可以使用一个变量存储: args =
-
使用select函数处理
- select("#",...) -- 返回可变参数的长度
- select(n,...) -- 如果使用一个值接收,就返回第n个数;如果不接受,就会返回包括第n个数的列表
function foo(index,...) local len = select("#",...) print("len:",len) local n = select(index,...) print("n:",n) print("the"..index.."is list:"..select(index,...)) -- 这里也只是打印一个值 print(select(index,...)) end foo(2,2,1,0,1) --[[ len: 4 n: 1 the2is list:1 1 0 1 ]]--
-
-
运算符
运算符
操作符 | 描述 | 实例 |
---|---|---|
+ | 加法 | A + B 输出结果 30 |
- | 减法 | A - B 输出结果 -10 |
* | 乘法 | A * B 输出结果 200 |
/ | 除法 | B / A w输出结果 2 |
% | 取余 | B % A 输出结果 0 |
^ | 乘幂 | A^2 输出结果 100 |
- | 负号 | -A 输出结果 -10 |
关系运算符
操作符 | 描述 | 实例 |
---|---|---|
== | 等于,检测两个值是否相等,相等返回 true,否则返回 false | (A == B) 为 false。 |
~= | 不等于,检测两个值是否相等,不相等返回 true,否则返回 false | (A ~= B) 为 true。 |
> | 大于,如果左边的值大于右边的值,返回 true,否则返回 false | (A > B) 为 false。 |
< | 小于,如果左边的值大于右边的值,返回 false,否则返回 true | (A < B) 为 true。 |
>= | 大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false | (A >= B) 返回 false。 |
<= | 小于等于, 如果左边的值小于等于右边的值,返回 true,否则返回 false | (A <= B) 返回 true。 |
逻辑运算符
操作符 | 描述 | 实例 |
---|---|---|
and | 逻辑与操作符。 若 A 为 false,则返回 A,否则返回 B。 | (A and B) 为 false。 |
or | 逻辑或操作符。 若 A 为 true,则返回 A,否则返回 B。 | (A or B) 为 true。 |
not | 逻辑非操作符。与逻辑运算结果相反,如果条件为 true,逻辑非为 false。 | not(A and B) 为 true。 |
其他运算符
操作符 | 描述 | 实例 |
---|---|---|
.. | 连接两个字符串 | a..b ,其中 a 为 "Hello " , b 为 "World", 输出结果为 "Hello World"。 |
# | 一元运算符,返回字符串或表的长度。 | #"Hello" 返回 5 |
例子:
a = "hello"
b = "world"
print( a..b )
print("a len is",#a)
--[[
helloworld
a len is 5
]]--
字符串
-
表达方式
- 单引号:‘www'
- 双引号: "runoob"
- [[与]]间的一串字符
-
string1 = "Lua" print("\"字符串 1 是\"",string1) string2 = 'runoob.com' print("字符串 2 是",string2) string3 = [["Lua 教程"]] print("字符串 3 是",string3)
数组
-
数组的索引:索引值是从1开始的,但是也可以指定0开始,并且也可以以负数为数组索引值。
-
array = {} for i= -2, 2 do array[i] = i *2 end for i = -2,2 do print(array[i]) end -- [[ -4 -2 0 2 4 ]]--
-
多维数组思想转化:一维数组的元素为数组
迭代器
- 泛型for迭代器
for k,v = pairs(t) do
print(k,v)
end
- 无状态迭代器:在for的控制语句中使用自己定义的函数实现
例
function square(iteratorMaxCount,currentNumber)
if currentNumber<iteratorMaxCount
then
currentNumber = currentNumber+1
return currentNumber, currentNumber*currentNumber
end
end
for i,n in square,3,0
do
print(i,n)
end
table
序号 | 方法 & 用途 |
---|---|
1 | table.concat (table [, sep [, start [, end]]]):concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开。 |
2 | table.insert (table, [pos,] value):在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾. |
3 | table.remove (table [, pos])返回table数组部分位于pos位置的元素. 其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元素删起。 |
4 | table.sort (table [, comp])对给定的table进行升序排序。 |
Lua模块与包
-
模块类似于一个封装库,Lua加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以API接口的形式在其他地方调用,有利于代码的重用和降低代码的耦合度
-
lua模块是由变量、函数等已知元素组成的table。因此创建一个模块很简单,就是创建一个table,然后把需要导出的常量、函数放入其中,最后返回一个table就行。
-
-- ysmModule.lua 文件名字 ysmModule = {} -- 定义一个常量 ysmModule.constant = "this is a changliang" -- 定义一个函数 function ysmModule.func1() print("this is a func1") end -- 定义一个私有函数 function func2() print("this is a func2") end function ysmModule.func3() func2() end return ysmModule --template.lua require("ysmModule") print(ysmModule.constant) ysmModule.func3() ysmModule.func1()
Lua元素(Metatable)
-
Lua提供元表使得允许改变table的行为,每个行为关联对应的方法
-
操作方法
- setmetatable(table,metatable):对指定table设置元表,如果元表中存在__metatable的键值,setmetatable会失败
- getmetatable(table):返回对象的元素
-
__index方法
-
这是metatable最常用的键。当你通过键来访问table的时候,如果这个键没有值,那么lua就会寻找该table的metatable中的__index键,如果__index包含一个表格,lua会在表格中查找相应的键。
-
-- 示例 mytable = {} mytable["a"] = "1" mymatatable = {} mymatatable["ma"] = "11" mytable = setmetatable(mytable,{__index = mymatatable}) print(mytable.a) print(mytable.ma) mytable = setmetatable(mytable,{__index=function (mytable,key) -- 这里也表示这个只能有一个__index,是覆盖的 if key=="key2" then return "metatablevalue" end return nil end}) print(mytable.a,mytable.ma,mytable.key2)
-
-
__newindex方法
-
__newindex元方法用来对表更新。
-
__newindex的方法和index的区别在于不会被覆盖
-
当你给表的一个缺少的索引赋值,解释器就会查找__newindex元方法,如果存在则调用这个函数而不进行赋值操作
-
-- newindex mytable = nil -- 释放内存 mymetatable = {} mytable = setmetatable({key1="value1"},{__newindex=mymetatable}) mytable.key2 = "value2" print(mytable.key1,mymetatable.key2) mytable.key3 = "value3" print(mytable.key1,mymetatable.key2,mymetatable.key3) print(mytable.key1,mytable.key2,mytable.key3) -- 新增的值是在元表中的 mytable = setmetatable(mytable,{__newindex = function (mytable,key,value) rawset(mytable,key,"\""..value.."\"") end}) print(mytable.key1,mytable.key2,mytable.key3) mytable.key2 = "rawset2" mytable.key3 = "rawset3" print(mytable.key1,mytable.key2,mytable.key3) print(mytable.key1,mymetatable.key2,mymetatable.key3) testtable= {} mytable = setmetatable(mytable,{__newindex = testtable}) -- newindex不会覆盖 mytable.key4 = "key4" mytable.key5 = "key5" print(mytable.key1,mytable.key2,mytable.key3) print(mytable.key1,mymetatable.key2,mymetatable.key3) print(testtable.key4,testtable.key5) --[[ value1 value2 value1 value2 value3 value1 nil nil value1 nil nil value1 "rawset2" "rawset3" value1 value2 value3 value1 "rawset2" "rawset3" value1 value2 value3 key4 key5 ]]--
-
-
其他的metatable键代表的含义
-
模式 描述 __add 对应的运算符 '+'. __sub 对应的运算符 '-'. __mul 对应的运算符 '*'. __div 对应的运算符 '/'. __mod 对应的运算符 '%'. __unm 对应的运算符 '-'. __concat 对应的运算符 '..'. __eq 对应的运算符 '=='. __lt 对应的运算符 '<'. __le 对应的运算符 '<='.
-
-
协同程序(coroutine)
-
定义:Lua协同程序与线程比较类似:拥有独立的栈,独立的局部变量、独立指令指针、同时又与其它协同程序共享全局变量和其他大部分东西
-
线程和协程的区别
- 进程可以同时运行多个线程,协同程序需要彼此协作运行
- 在任意一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起来时候才被挂起
-
方法 描述 coroutine.create() 创建 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用 coroutine.resume() 重启 coroutine,和 create 配合使用 coroutine.yield() 挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果 coroutine.status() 查看 coroutine 的状态 注:coroutine 的状态有三种:dead,suspended,running,具体什么时候有这样的状态请参考下面的程序 coroutine.wrap() 创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复 coroutine.running() 返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 corouting 的线程号 -
示例
-
co = coroutine.create( function (i) print(i) end ) -- 创建一个协同 coroutine.resume(co,1) -- 启动协同 print(coroutine.status(co)) print("---------------") co = coroutine.wrap( function (i) print(i) end ) -- 是create和resume的结合体 co(1) print("...........") co2 = coroutine.create( function () for i=1,10 do -- body print(i) if i==3 then print(coroutine.status(co2)) --想知道此时co2的运行状态 print(coroutine.running()) -- 返回正在跑的coroutine end coroutine.yield() -- 将协程挂起,当协程再次运行的时候,会从这个部分运行 end end ) coroutine.resume(co2) coroutine.resume(co2) coroutine.resume(co2) coroutine.resume(co2) print(coroutine.status(co2)) -- suspended print(coroutine.running()) -- 挂起不算是运行 print("=================") function foo(a) print("foo print",a) return coroutine.yield(2*a) end co3 = coroutine.create(function (a,b) print("first print",a,b) local r = foo(a+1) print("second print",r) local r,s = coroutine.yield(a+b,a-b) print("third print",r,s) return b,"end" end) print("main",coroutine.resume(co3,1,10)) print("-------------") print("main",coroutine.resume(co3,"r")) print("-------------") print("main",coroutine.resume(co3,"x","y")) print("-------------") print("main",coroutine.resume(co3,"x","y")) print("-------------") -- 其实就是yeild和resume之间的传值 -- resume返回的值为:是否可以传和yeild的参数 -- yeild返回值为:resume的参数,并且yeild会阻塞 --[[ 1 dead --------------- 1 ........... 1 2 3 running thread: 00D7D7D8 4 suspended nil ================= first print 1 10 foo print 2 main true 4 ------------- second print r main true 11 -9 ------------- third print x y main true 10 end ------------- main false cannot resume dead coroutine ------------- ]]--
-
-
读写文件
-
Lua I/O库用于读取和处理文件。分为简单模式、完全模式
- 简单模式:拥有一个当前输入文件和一个当前输出文件,并且提供针对这些文件相关操作
- 完全模式:使用外部的文件句柄来实现。它以一种面向对象的形式,将所有的文件操作定义为文件句柄的方法
-
打开文件操作
-
file = io.open(filename,[,mode])
-
打开文件模式
-
模式 描述 r 以只读方式打开文件,该文件必须存在。 w 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。 a 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留) r+ 以可读写方式打开文件,该文件必须存在。 w+ 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 a+ 与a类似,但此文件可读可写 b 二进制模式,如果文件是二进制文件,可以加上b + 号表示对文件既可以读也可以写
-
-
两种模式的代码如下
-
print("========简单模式======")
file = io.open("test.txt","r")
io.input(file)
print(io.read())
io.close(file)
-- 附加的方式打开只写文件
file = io.open("test.txt","a")
io.output(file) -- 这个用来写入文件
io.write("--test.lua 文件末尾注释")
io.close(file)
print("=======完成模式======")
file = io.open("test.txt","r")
print(file:read()) -- 默认读取第一行
file:close()
file = io.open("test.txt","a")
file:write("--test\n")
file:close()
-- 按行读取文件
for line in io.lines("test.txt") do
-- body
print(line)
end
Lua错误处理
-
错误类型
- 语法错误
- 运行错误
-
运行错误的方式比较
- assert:不是预想值的时候结束程序
- error: 会直接结束程序的运行
- xpcall:不会结束程序,但是出现异常的时候,直接抛出来
- 运行例子:
function add(a,b) assert(type(a)=="number","a is not a number") -- 这里出现了错误,就会整个停止程序 assert(type(b)=="number","b is not a number") return a+b end print(add(1,1)) function addErr(a) -- error("a is not a number",2) -- 一旦出现错误了就要将程序停止 print("ssss") end addErr(a) function myfunction() n = n /nil end function myerrorHandler(err) print("ERROR:",err) end status = xpcall(myfunction,myerrorHandler) -- 这样不会将程序停止 print(status) print("===========")
Lua数据库访问
-
lua数据库的操作库:LuaSQL。它是开源的,支持的数据库有:ODBC、ADO、Oracle、SQLite和PostgreSQL
-
安装方式如下:
wget http://luarocks.org/releases/luarocks-2.2.1.tar.gz tar zxpf luarocks-2.2.1.tar.gz cd luarocks-2.2.1 ./configure; sudo make bootstrap if [ $? -ne 0 ]; then echo "设置位置错误" else echo "设置位置成功" fi luarocks install luasocket
-
安装不同数据库驱动
luarocks install luasql-sqlite3 luarocks install luasql-postgres luarocks install luasql-mysql luarocks install luasql-sqlite luarocks install luasql-odbc
-
最好不要再window中下载,这里在liunx中下载postgreSQL的驱动,并且这里安装特别的麻烦。
# 安装postgreSQL之后,同时要安装libpq-dev。需要提供头文件,否则会出现如下错误: Error: Could not find expected file libpq-fe.h, or libpq-fe.h for PGSQL -- you may have to install PGSQL in your system and/or pass PGSQL_DIR or PGSQL_INCDIR to the luarocks command. Example: luarocks install luasql-postgres PGSQL_DIR=/usr/local # 先安装libpq-dev apt-get install libpq-dev # 然后在运行安装 luarocks install luasql-postgres PGSQL_INCDIR=/usr/include/postgresql PGSQL_LIBDIR=/usr/lib
-
示例
Postgres = require "luasql.postgres" print(Postgres) env = Postgres.postgres() print(env) conn = env:connect("lua", "postgres", "postgres", "119.23.67.53", 5432); conn:execute"SET NAMES UTF8" cursor, errorString = conn:execute("select * from student"); print(cursor, errorString); print(cursor:numrows()); row = cursor:fetch({}, "a"); -- 将表中的数据放入到表中 while row do print(string.format("Id: %s, Name: %s", row.id, row.name)); row = cursor:fetch(row, "a"); -- a应该就是追加的方式 end cursor:close(); conn:close(); env:close(); -- [[ table: 0x24af0c0 PostgreSQL environment (0x24af968) PostgreSQL cursor (0x247ed48) nil 2.0 Id: 1, Name: tom Id: 2, Name: jim ]]--
linux上安装lua和luarocks的配置文件
echo "下载安装包"
cd /root/lua
rm -rf lua-5.3.0
rm -rf lua-5.3.0.tar.gz
curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gz
tar zxf lua-5.3.0.tar.gz
cd lua-5.3.0
make linux test
make install
# 要是安装错误:readline/readline.h: No such file or directory
# apt-get install libreadline-dev
echo "安装luarocks"
cd /root/luarocks
wget http://luarocks.org/releases/luarocks-2.2.1.tar.gz
tar zxpf luarocks-2.2.1.tar.gz
cd luarocks-2.2.1
./configure; sudo make bootstrap
if [ $? -ne 0 ]; then
echo "设置位置错误"
else
echo "设置位置成功"
fi
luarocks install luasocket