以下代码都经过测试可以运行,可以使用下面的lua在线运行查看效果,建议在Linux上搭建Lua运行环境(在官网下载源代码,编译生成一个可执行程序即可)。
Lua在线运行测试:https://www.bejson.com/runcode/lua/
Lua源码下载地址:http://www.lua.org/ftp/
1、if … else …
下面讲解lua变量声明以及条件判断语句
local a = 0 -- 局部变量,number类型
b = false -- 全局变量,bool类型
c = "Hello" -- string类型
d, e, f = 0, 1.1 -- d=0,e=1.1,f=nil
g = 1 .. 2 -- g=12, ..会拼接前后的字符串
if a == 0 and b ~= 0 then -- lua中false不等于0
print("1")
elseif c >= 0 or not d then
print("2")
else
print("3")
end
输出结果:1
2、函数
函数大致分为:局部函数,全局函数和成员函数。函数前加local就是局部函数,只能在本文件中被调用;不加local就是全局函数,可以在其他文件调用该函数;成员函数是定义在table里的函数,需要通过table调用。
local function hello() -- 局部函数,只允许在本文件内调用
print("Hello world")
end
hello() -- 调用函数
输出结果:
Hello world
function average(...) -- 全局函数,...表示可变参数
result = 0
local arg={...} -- arg为一个表,局部变量,里面存放的是入参
for i, var in ipairs(arg) do
result = result + var -- 入参累加
end
print("形参个数:" .. #arg .. " 个")
return result/#arg
end
print("平均值为:"..average(10,5,3,4,5,6)) -- 调用求平均值函数average()
输出结果:
形参个数:6 个
平均值为:5.5
People = {age = 20} -- 声明一个类(table)
function People.sayHi(self, name) -- 类的成员函数
print(name, self.age)
end
People.sayHi(People, "Zhangsan") -- 直接调用类的成员函数
People:sayHi("Lisi") -- 将People自身作为实参传入函数,效果同上
输出结果:
Zhangsan 20
Lisi 20
3、table和for循环
table可以看作是C++里的类,里面可以放变量也可以放函数,可以在任意时候往table里增加变量或函数。
People = {hello="Hello lua", world="World"} -- 初始化table
People.num = 100 -- 添加元素并赋值
People["name"] = "ZhangSan" -- 添加元素并赋值
print(People.num) -- 打印num元素的值
print(People["world"]) -- 打印world元素的值
for key, var in pairs(People) do -- 遍历数组
print(key, var) -- 打印索引和值,索引从1开始
end
输出结果:
100
World
num 100
name ZhangSan
world World
hello Hello lua
4、面向对象
lua不支持原生的面向对象和多态,但可以通过一些方法事项。以下两段代码需要放在两个文件里:module.lua和test.lua。module可以看作一个类的封装,运行时只调用test.lua。
-- module.lua文件,文件名就是module名
module = {} -- 定义一个名为module的模块
module.publiclVar = "公共成员变量" -- 类成员变量
local privateVar = "私有成员变量" -- 局部变量,只能本文件访问
function module.publicFun() -- public公共函数,可以在外部访问
io.write("这是一个公有函数!\n") -- 等同于print()
end
local function privateFun() -- private私有函数,只能在本文件内访问
print("这是一个私有函数!")
end
return module
-- test.lua文件
require("module") -- 执行require 后会返回一个由模块常量或函数组成的table,并且还会定义一个包含该table的全局变量。
print(module.publiclVar) -- 访问module里的成员变量publiclVar,require()函数已经声明了module,可以直接访问
module.publicFun() -- 调用module里的成员函数publicFun(),如果调用私有函数privateFun()就会报错
输出结果:(调用test.lua)
公共成员变量
这是一个公有函数!
5、继承和派生
同样,lua也不支持原生的多态,但可以自己实现new函数达到相同的效果。父类在new方法里将所有属性和方法都拷贝给子类,子类在new方法里调用父类的new函数获取父类所有属性和方法,然后再增加自己特有的属性和方法,以此来实现多态,示例代码如下:
Father = {name = "Zhangsan", age = 50} -- 父类成员变量声明和初始化
Father.hello = function() -- 父类成员函数
print("Hello world!")
end
function Father.new(iName) -- 父类new方法
local ins = {}
for key, var in pairs(Father) do
ins[key] = var -- 将父类所有方法和属性都拷贝给子类
end
ins.name = iName
return ins -- 返回实例化的父类对象,子类负责接受
end
Son = {} -- 子类
function Son.new() -- 子类new方法
local ins = Father.new("Lisi") -- 继承父类的所有属性和方法
ins.sports = "Basketball" -- 添加子类特有属性或方法
return ins -- 返回实例化的子类对象
end
-- 开始测试
child = Son.new() -- 实例化子类
child.hello() -- 调用父类成员函数
print(child.sports) -- 访问子类属性或方法
输出结果:
Hello world!
Basketball
6、编程技巧
使用goto语句模拟continue
for key, var in pairs(People) do -- 遍历数组
if key == 0 then
goto continue
end
print(key, val)
::continue::
end
7、OpenResty常用命令
OpenResty函数库请参考:https://www.kancloud.cn/qq13867685/openresty-api-cn/159139
ngx.var.VAR_NAME -- 读写 Nginx 变量值
ngx.log(log_level, ...) -- 将参数拼接起来,按照设定的日志级别记入
ngx.ctx -- 请求lua上下文
ngx.header[HEADER] -- 修改、添加、或清除当前请求待发送的 HEADER 响应头信息。
ngx.shared.DICT -- 获取共享内存名为 DICT 的 lua 字段
ngx.shared.DICT:get(key) -- 从 ngx.shared.DICT 字典中获取名为 key 的键值
ngx.shared.DICT:set(key, value) -- 无条件在基于共享内存的字典 ngx.shared.DICT 中设置一个 key-value (键-值)对
ngx.req.get_headers() -- 获取请求头信息,函数返回一个table
ngx.req.get_uri_args() -- 获取当前请求的所有URL 查询参数
ngx.req.set_uri_args(args) -- 用 args 参数重写当前请求的 URI 请求参数
ngx.req.set_uri(uri, jump?) -- 用 uri 参数重写当前请求,jump为 true 时,此函数将不会返回;为 false 时只有当前请求的 URI 被改写
ngx.req.get_body_data() -- 取回内存中的请求体数据。本函数返回 Lua 字符串而不是包含解析过参数的 Lua table
ngx.req.get_method() -- 获取当前请求的HTTP请求方法名称
ngx.req.read_body() -- 同步读取客户端请求体,不阻塞 Nginx 事件循环
ngx.status -- 读写当前请求的响应状态码。这个方法需要在发送响应头前调用。
ngx.say(...) -- 与 ngx.print 相同,同时末尾添加一个回车符
ngx.exit(status) -- 结束请求
ngx.time() -- 返回从1970年到现在经过的秒数。
ngx.now() -- 返回一个从1970年到现在经过的秒数,浮点型的数字,小数部分是毫秒
ngx.update_time() -- 强行更新Nginx当前时间缓存,涉及系统调用,有一些系统开销
ngx.timer.at(delay, callback, user_arg1, ...) -- 创建一个 Nginx 定时器
ngx.sleep -- 无阻塞休眠(使用定时器实现,事件精确到1毫秒)
ngx.worker.exiting() -- nginx的worker进程退出
ngx.worker.pid() -- 返回当前 Nginx 工作进程的进程 ID (PID)
ngx.decode_args(args) -- 将 URI 编码的查询字符串解码为 Lua 表
ngx.encode_args(args) -- 根据 URI 编码规则,将 Lua 表编码成一个查询参数字符串
ngx.location.capture(uri, options?) -- 向 uri 发起一个同步非阻塞 Nginx 子请求。
ngx.unescape_uri(str) -- 将转义过的str解码
ngx.re.match((subject, regex, options?, ctx?, res_table?)) -- 使用 Perl 兼容正则表达式 regex 匹配字符串 subject,并使用可选的参数 options 作为正则表达式选项。
ngx.re.sub(subject, regex, replace, options?) -- 使用 Perl 兼容正则表达式 regex 匹配字符串 subject,将第一个结果替换为字符串或函数类型参数
replace ngx.socket.tcp() -- 创建并得到一个 TCP 或 unix 域流式 socket 对象
ngx.socket.udp() -- 创建并得到一个 UDP 或 unix 域数据报 socket 对象