学习目标:
提示:
- lua学习
安装Lua:
# 下载包
wget http://www.lua.org/ftp/lua-5.4.0.tar.gz
# 解压
tar zxf lua-5.4.0.tar.gz
# 进入lua-5.4.0中编译,编译成功后,会在src目录里面看到lua.c和luac.c文件
make linux test
# 安装lua
make install
# 刷新动态库链接
ldconfig
# 验证是否安装成功
lua -v
进入lua控制台
lua
执行lua文件:
# 创建目录
mkdir lua
# 进入到目录中
cd lua
# 编写lua脚本
vim aaa.lua
# 执行lua文件
lua aaa,lua
语法:
关键字:
注释:
-- 单行注释
--[[
多行注释内容
]]
8种数据类型
- nil(空):无效值,表示未被定义
- boolean(布尔):true 和 false
- number(数值):integer整型、float双精度的浮点型,math.type()查看类型
- string(字符串):双引号或单引号
- userdata(用户数据):脚本用户只能使用,而不能对其进行定义
- function(函数)
- thread(协程):协同程序,与线程比较类似
- table(表):{},数组、集合
type(nil)
type(123)
type("aaa")
type(true)
type({})
-- 输出字符串长度
print(#"123")
-- 字符串拼接
print("123".."456")
-- a=[[字符串]],注意,使用该方式,如果字符串中有转义字符,无法转义
print("[[aaa\"bbb\"]]") --输出:aaa\"bbb\"
-- 数值和字符串的自动转换
print("1"+2) --输出:3
-- tonumber(字符串)将字符串转为数值,tostring(数值)将数值转为字符串
print(tonumber("333")) --输出:3
-- string.len(字符串)或字符串:len()
print(string.len("aaa")) --输出:3
print("bbb":len()) --输出:3
-- 重复3次
print(string.rep("1a",3)) --输出:1a1a1a
-- 翻转
print(string.reverse("1a",3)) --输出:a1
-- 大写
print(string.upper("1a")) --输出:1A
print("1a":upper()) --输出:1A
-- 截取
print(string.sub("123",1,2)) --输出:12
print(string.sub("123",1,-2)) --输出:12
print(string.sub("123",1,-1)) --输出:123
-- 占位输出
print(string.format("num=%d",123)) --输出:num=123
print(string.find("123","2")) --输出:2
print(string.find("123","23")) --输出:3
-- 占位替换
print(string.gsub("123","1","a")) --输出:a23
- table(表):{},数组、集合、元表、元方法
-- 使用a = {}构造表a,直接输出a会返回表的地址,a只是表的引用
t={}
-- 表添加元素采用的是a[key] = value,key-value的方式
t[1]="sssss"
t["aaa"]=22
-- 将nil给表元素,可以将表元素删除
t=nil
-- 当多个表名引用同一张表时,任何一个引用改变了表数据,其它引用的表数据也会改变
m=t
m["aaa"]=33
print(t["aaa"]) -- 输出:33
-- 表名.key名=value的方式插入数据,可以使用表名.key名的方式调用表元素等价于表名[key名]
t.cc=99
-- 表构建,相当于list={[1]="a",[2]="b",[3]="c",[4]="d",[5]="e",[6]="f"}
list={"a","b","c","d","e","f"}
print("list:first element is "..list[1]);
-- 记录构建,相当于entity={["id"]=1,["name"]="zhangsan",["age"]=23}
entity={id=1,name="zhangsan",age=23}
print("entity:name is "..entity.name);
-- 混合构建,相当于mix={["id"]=2,[1]="a",[2]="b",["name"]="sssss",[3]="c"}
mix={id=2,"a","b",name="sssss",[3]="c"}
print(mix[1]); -- 输出:a
print(mix.name); -- 输出:sssss
t={1,2,3,4}
-- 在表t开头插入9,其它元素依次后移一位
table.insert(t,1,9);
-- 在表t末尾插入10
table.insert(t,10);
-- 移除表t第一个元素,其它元素依次前移一位
table.remove(t,1);
-- 移除表t最后一位元素
table.remove(t);
#
array = {}
array.func = function()
print("这是一个函数")
end
array.func()
-- 排序
table.sort(数组,排序规则)
-- pairs迭代器和ipairs迭代器
table={1,2,3,id="10021","a","b",name="ls"}
print("pairs result is:");
-- pairs可以遍历出所有的元素,但是遍历的元素不是按顺序的
for k,v in pairs(table) do
print(k,v);
end
-- 只输出key=1,2,3,4....
print("ipairs result is:")
--[[ipairs只能遍历序列(key从1开始,直到key不连续为止),输出顺序会按定义的顺序输出]]
for k,v in ipairs(table) do
print(k,v)
end
thread
- coroutine.create:创建一个协程,返回的是corontine,参数是一个函数
- coroutine.resume:重新启动协程,配合create使用
- coroutine.yield:挂起协程
- coroutine.status:返回当前协程状态,suspended(挂起)、running(运行)、dead(死亡)
- coroutine.wrap:创建一个协程,返回一个函数,一旦调用这个函数,就会进入coroutine,和create类似。
- coroutine.running:返回正在运行的coroutine,返回的是coroutine的线程号
function run(data)
-- 当前协程状态
print("1:"..coroutine.status(co));
data = data+1;
-- 打印 "co" 1 2
print("co", 1, data);
-- 当前协程的线程号
print(coroutine.running());
-- 当前协程挂起
coroutine.yield()
print("2:"..coroutine.status(co));
print(coroutine.running())
data = data+1;
-- 打印 "co" 2 3
print("co", 2, data)
end
function test(data)
-- 当前协程的线程号
print(coroutine.running())
data = data+1;
print("co2",3, data)
-- 协程挂起
coroutine.yield()
print(coroutine.running())
data = data+1;
print("co2",4,data)
end
-- create方式创建协程
co = coroutine.create(run);
print("create status is:"..coroutine.status(co));
-- wrap方式创建协程
co2 = coroutine.wrap(test);
print("wrap status is:"..coroutine.status(co2));
data = 1
-- 启动co协程,参数一:协程,参数二:数据
coroutine.resume(co, data)
-- 启动co2协程
co2(data);
print("co first resume end status:"..coroutine.status(co));
print("main", data);
-- 重新启动co协程
coroutine.resume(co, data)
print("co second resume end status:"..coroutine.status(co));
-- 启动死亡协程,会报出cannot resume dead coroutine
print("co third resume:",coroutine.resume(co,data));
-- 重新启动co2协程
co2(data);
元表(metatable)和元方法(metamethod):
- 元表是Lua中的一个特殊表,用于定义自定义类型的行为和操作
- 元方法是元表中的特殊键,用于指定对象的操作行为,例如相加、相减等。
- 可以使用元表和元方法来实现对象的操作符重载和自定义类型的行为。
-- 创建元表
local myMetatable = {}
-- 定义元方法
myMetatable.__add = function (a, b)
return a + b
end
-- 创建对象
local obj1 = 10
local obj2 = 20
-- 设置元表
setmetatable(obj1, myMetatable)
-- 调用元方法
local result = obj1 + obj2
print(result) -- 输出: 30
运算符
算术运算符
- 加(+)
- 减(-)
- 乘(*)
- 除(/)
- 取负(-)
- 取模(%)
- 取整除(//)
- 幂运算(^)
– 注意:两个操作数都是整型并且不是除法时,结果才是整型,否则就是浮点型
-- math数学库
> math.floor(5.6)
> math.random(1,20)
逻辑运算符:
- nil:默认为false
- and:前面的操作数如果为false,就返回前面的操作数;否者返回后面的操作数
- or:前面的操作数为true,则返回前面的操作数,否者返回后面的
- not:取反
> true and "返回该值" -- 返回改值
> false and "任意值" -- 返回false
> 4==4 and 5==5 --true
> "123"==123 --false
> "123" and 4==4 --true
> "123" or 4=5 --123
> not "123" and 4==4 --false
> 1 ~= 0 --true
> 4 and 5 --5
> 4 or 5 --4
> not 4 and 5 --false
> nil and 5 --nil
> nil or 5 --5
比较运算符:
- 等于(==)
- 不等于(~=)
- 大于(>)
- 小于(<)
- 大于等于(>=)
- 小于等于(<=)
全局变量和局部变量(local修饰)
-- 全局变量i
i = 10;
do
-- 局部变量x
local x = i - 1;
i = i - 1;
-- 局部代码块打印x,输出9
print(x);
end
-- 打印i,输出9
print(i);
-- 局部代码块之外打印x,输出nil
print(x);
function 函数
- 函数可以返回一个或多个值,使用关键字return
--语法
function 函数名(入参1,入参2,...)
具体代码
end
--调用方式
函数名(参数1,参数2,...)
function f(...) --三个点表示函数的参数个数不确定
function f(a,b,...) --函数有两个固定的参数,其他参数不确定
f(3) --a=3,b=nil,arg={n=0}
f(3,4) --a=3,b=4,arg={n=0}
f(3,4,5,8) --a=3,b=4,arg={5,8;n=2}
function compute(a,b)
local x = a+b
local y = a-b
return x,y
end
i,j = compute(5,2)
print(i.." : "..j)
判断语句
-- 创建函数,传入参数a
function panduan(a)
if 表达式1 then
语句块1
elseif 表达式2 then
语句块2
else
语句块3
end
-- 函数结尾
end
-- 输出
print("please enter a number:");
-- 输入
n=io.read("*n");
-- 调用函数
panduan(n);
循环语句
while
-- 语法一
while 循环条件(符合该循环条件则继续循环) do
循环体
end
-- 求和
function whiletest(n,sum)
local i = 0;
while i<=n do
sum=sum+i;
i=i+1;
end
return sum;
end
repeat
--语法二
repeat
循环体
until 循环条件(符合该循环条件,则退出循环)
-- 求和
function repeattest(n,sum)
local i = 0;
repeat
sum=sum+i;
i=i+1;
until i>n
return sum;
end
for
--语法三
for 变量=初始值,终止值,步长 do
循环体
end
-- 求和
function fortest(n,sum)
for i=0,n,1 do
sum=sum+i;
end
return sum;
end
print("Please enter a number:");
n=io.read("*n");
print("while:add from 1 to "..n.." and the result is: "..whiletest(n,0));
print("for:add from 1 to "..n.." and the result is: "..fortest(n,0));
print("repeat:add from 1 to "..n.." and the result is: "..repeattest(n,0));
函数库
String.sun(字符串,开始下标,终止下标) 截取字符串
String.tonumber(字符串,进制) 字符串转数字类型
select()函数它的作用是允许你指定从第几个返回值开始取值。
当第一个参 数为“#”时,select()简单返回其余参数的个数
print("#", "a","b","c") -- 输出:3
当第一个 参数为一个数字时,select()返回从这个位置开始直到最后一个的参数
print(2, "a","b","c") -- 输出:b,c
print():打印
tostring(123):返回字符串“123”
tonumber(参数):将参数转化为数字
type():返回参数的类型名
rawset(表,键,值):更改表中指定键对应的值,返回表的指针
rawget(表,键):获取表中指定键对应的值,当键不存在时返回nil
rawequal(num1,num2):比较两个参数是否相等,返回boolean值(相等为true)
dofile(程序块):打开并执行一个lua程序块
next(表,键):允许程序遍历表中每个字段,返回下一个键和对应的值。此函数只能用于数字做键的表。
pairs和ipairs迭代器。pairs可以遍历表中所有的键,并且除了迭代器本身以及遍历表本身还可返回nil;但是ipairs则不能返回nil,只能返回0,如果遇到nil则退出。它只能遍历到表中出现的第一个不是整数的键。
require(文件名):搜索目录加载文件,并判断是否文件已经加载。使用本函数前一般需要用package.path(路径)来指定搜索路径。
表库
table.concat(表,分隔符,开始下标,结束下标)返回参数中表内从开始下标到结束下标中的所有数组部分,并用分隔符隔开。后三个参数为可选参数。
table.insert(表,键,值)在指定表中插入一个指定的键和值。参数键可以省略。省略插入的值将被放置于表的最后一位。
table.maxn(表)返回指定表中所有正数键值中最大的键。如果不存在键为正数的元素,则返回0.
table.remove(表,键)删除并返回表的数组部分指定键的元素。其后的元素会被前移。如果省略键参,则从最后一个元素删起。
table.sort(表,comp)对指定的表进行升序排序。comp可选参数,此参数是一个外部函数,可以自定义sort函数的排序标准,此函数应满足以下条件:接受两个参数a,b,并返回一个布尔型的值,当a应该排在b前面时,反悔true,否则返回false。
table.foreachi(表,function(i,v))会期望一个从1开始的连续整数范围,遍历表中的键和值逐对进行function(i,v)操作。
table.foreach(表,function(i,v))会对整个表进行遍历。
table.getn(表)返回表中元素的个数
table.setn(表,个数)设置表中元素的个数
字符串库
string.len(字符串)字符串的长度
string.rep(字符串,数值)返回字符串的n个拷贝
string.lower(字符串)字符转小写
string.lower(字符串)字符转小写
string.sub(字符串,参数,参数)截取部分字符串
string.byte(字符串,参数)返回字符串中参数所指向字符的ascii码
string.char(参数,参数,参数,...)将ascii码转化为对应的字符
string.gsub(字符串,被替换的字符串,替换的字符串,参数)替换字符串的一部分,参数为需要替换的个数
string.find(字符串,参数,开始位置)查找在字符串中的某一部分,返回索引。
string.format(格式化字符串,格式化参量)
操作系统库
os.clock()返回一个程序使用cpu时间的一个近似值
os.time(...)按参数的内容返回一个时间值(数字),若不带参数则返回当前时间。
os.tmpname()返回一个临时文件名
os.getenv(varname)返回当前进程的环境变量varname的值,若变量没有定义则返回nil
os.remove(filename)删除文件
os.rename(oldname,newname)更改文件或目录名
os.exit(code)相当于C的exit函数,终止主程序
os.difftime(t2,t1)返回t1到t2相差的秒数
os.date(format,time)返回一个格式化日期、时间的字符串或表
流和文件库
简单IO:所有操作都是在两个当前文件之上
完全IO:为了更好的控制输入输出流,而添加了对输入输出文件句柄操作的一种模式。
io.read(参数)
参数:
*all 读取整个文件
*line 读取下一行
*number 从串中转换出一个数值
num 读取num个字符串
io.write()
与print的用法类似。可以用format函数进行格式化输出
io.flush()输出所有缓冲区的内容到输出文件
io.close()关闭打开的文件
io.open(filename,mode)按指定模式打开一个文件,成功则返回文件句柄,失败则返回nil+错误信息
mode:
r 读
w 写
a 添加
r+ 更新,之前数据被保存
w+ 更新,之前数据被删除
a+ 添加更新,之前数据被保存,只允许在文件尾进行添加
模块
创建模块
-- 创建模块
local mymodule = {}
function mymodule.add(a, b)
return a + b
end
function mymodule.subtract(a, b)
return a - b
end
return mymodule
调用模块
-- 加载模块
local mymodule = require("mymodule")
-- 使用模块中的函数
local result = mymodule.add(3, 4)
print(result) -- 输出: 7
闭包(closure):
- 闭包是指一个函数以及与其相关的引用环境的组合。
- 在Lua中,闭包可以捕获并访问其创建时的变量和状态。
- 闭包在实际应用中常用于实现回调函数、函数工厂和状态管理等功能。
-- 创建闭包
function makeCounter()
local count = 0
return function()
count = count + 1
return count
end
end
-- 使用闭包
local counter = makeCounter()
print(counter()) -- 输出: 1
print(counter()) -- 输出: 2
元编程(metaprogramming):
- 元编程是指编写能够操作和生成代码的代码。
- 在Lua中,可以使用加载和执行字符串、动态创建函数和修改函数等技术实现元编程。
- 元编程在动态配置、代码生成和运行时扩展等领域具有广泛的应用。
-- 动态创建函数
local funcString = "return function(a, b) return a + b end"
local dynamicFunc = load(funcString)()
-- 调用动态创建的函数
local result = dynamicFunc(3, 4)
print(result) -- 输出: 7
红包分配
-- 定义列表
t={}
function initAmount(m,n)
local a = math.random(1,2*(math.floor(m/n)));
if n>1 and m<n then
initAmount(m,n);
elseif n==1 then
t[n]=m/100;
m = 0;
else
t[n]=a/100;
m = m-a;
n = n-1;
initAmount(m,n);
end
end
print("please enter an amount:");
amount = io.read("*n");
print("please enter share number:")
number = io.read("*n");
initAmount(amount*100,number);
print("the amount allocated is:");
for i = 1,number do
print(t[i])
end
参考资料:
-
Lua官方网站提供了详细的Lua语言参考手册、教程和文档,包括语法、标准库、C API等内容。 可以在官方网站上找到最新版本的文档:https://www.lua.org/docs.html
-
Nginx官方文档:Nginx官方网站提供了关于ngx_lua模块的文档和示例, 如何在Nginx中嵌入Lua脚本并扩展其功能:https://nginx.org/en/docs/
-
Apache官方网站提供了有关mod_lua模块的文档和示例, 如何在Apache中使用Lua扩展功能:https://httpd.apache.org/docs/
-
如何在Redis中使用Lua来处理数据和实现业务逻辑:https://redis.io/commands/eval
-
OpenResty官方网站提供了关于在OpenResty中使用Lua的详细文档和示例, 如何使用OpenResty构建高性能的Web应用程序:https://openresty.org/
-
如何扩展HAProxy的功能和实现自定义逻辑:https://www.haproxy.com/documentation/
-
Kong官方文档:Kong官方网站提供了关于在Kong中使用Lua插件的文档和示例,你可以了解如何扩展Kong API网关的功能和实现自定义业务逻辑:https://docs.konghq.com/