更多详细代码案例在GitHub,意见和问题请在公众号留言
https://github.com/kuweiguge/OpenResty-Lua-Labs
模块
Lua支持模块,你可以将一组相关的函数和变量组织在一个模块中。模块可以被其他Lua脚本引用。
-- mathlib.lua
local mathlib = {}
function mathlib.add(x, y)
return x + y
end
return mathlib
-- main.lua
local mathlib = require("mathlib")
print(mathlib.add(10, 20)) -- 30
元表和元方法
Lua提供了元表和元方法的概念,允许你定义和修改值的行为。例如,你可以使用元表来定义如何比较两个表,或者定义如何将两个表相加。
local set1 = {10, 20, 30} --集合set1
local set2 = {20, 30, 40} --集合set2
local mt = {} -- 空的元表
-- 定义元方法(计算两个集合的并集)
-- 遍历集合 a 和 b,将集合中的每个元素添加到result集合中。由于result集合是以集合元素为键的表,所以重复的元素会被覆盖,从而实现了并集的效果。
function mt.__add(a, b)
local result = {}
for _, v in pairs(a) do result[v] = true end
for _, v in pairs(b) do result[v] = true end
return result
end
-- 使用 setmetatable 函数将元表 mt 设置为 set1 和 set2 的元表。
-- 这样,当对这两个集合执行加法操作时,Lua 会调用元表中的 __add 方法。
setmetatable(set1, mt)
setmetatable(set2, mt)
local set3 = set1 + set2
for k in pairs(set3) do
ngx.say(k)
end
-- 需要注意的是,这段代码中的并集操作只适用于元素为数字或字符串的集合,如果集合中的元素是表或其他复杂类型,可能需要更复杂的处理方式。
setmetatable是 Lua 语言中的一个函数,用于设置或修改表的元表。元表是一种特殊的表,它可以改变表的行为,例如进行算术运算、比较运算、连接操作等。
在这段代码中,setmetatable(set1, mt)和setmetatable(set2, mt)将mt设置为set1和set2的元表。这样,当对set1和set2执行加法操作时,Lua 会调用元表中的__add方法。
__add是元表的一个特殊字段,用于定义加法操作。在这个例子中,__add方法被定义为计算两个集合的并集。
所以,setmetatable函数在这里的作用是,让set1和set2在执行加法操作时,按照我们自定义的方式(即计算并集)来执行。
Lua 中的元方法有很多,以下是一些常见的元方法及其作用:
-
__add(a, b): 对两个表进行加法操作时的行为。 -
__sub(a, b): 对两个表进行减法操作时的行为。 -
__mul(a, b): 对两个表进行乘法操作时的行为。 -
__div(a, b): 对两个表进行除法操作时的行为。 -
__mod(a, b): 对两个表进行取模操作时的行为。 -
__pow(a, b): 对两个表进行幂运算操作时的行为。 -
__unm(a): 对表进行取反操作时的行为。 -
__concat(a, b): 对两个表进行连接操作时的行为。 -
__len(a): 获取表长度时的行为。 -
__eq(a, b): 对两个表进行等于操作时的行为。 -
__lt(a, b): 对两个表进行小于操作时的行为。 -
__le(a, b): 对两个表进行小于等于操作时的行为。 -
__index(a, b): 访问表中不存在的字段时的行为。 -
__newindex(a, b, c): 对表中不存在的字段进行赋值操作时的行为。 -
__call(a, ...): 当表被当作函数调用时的行为。 -
__tostring(a): 当表被当作字符串使用时的行为。 -
__metatable: 用于保护元表,当设置为一个表时,将禁止对原表更改元表和获取元表。
这些元方法可以让你自定义表的行为,使其更符合你的需求。
协程
Lua支持协程,也称为轻量级线程。协程是一种可以暂停和恢复执行的计算机程序组件,非常适合用来处理异步任务。
local co = coroutine.create(function ()
for i = 1, 10 do
print(i)
coroutine.yield()
end
end)
coroutine.resume(co) -- 1
coroutine.resume(co) -- 2
首先,使用
coroutine.create函数创建了一个协程co。这个协程的主体是一个匿名函数,这个函数中有一个循环,循环体中首先输出一个数字,然后调用coroutine.yield函数让出 CPU 控制权,使协程暂停执行。
然后,使用coroutine.resume函数恢复协程的执行。每次调用coroutine.resume,协程会从上次暂停的地方继续执行,直到遇到下一个coroutine.yield调用或者到达函数末尾。在这个例子中,每次恢复协程,都会输出一个数字,然后协程再次暂停。
这段代码中,coroutine.resume(co)被调用了两次,所以当访问 /lesson9 路径时,会输出两个数字:1 和 2。
协程是一种可以暂停和恢复执行的轻量级线程,它可以用来实现非阻塞 IO、协作式多任务等功能。在 Nginx + Lua 的环境中,协程是实现高并发、高性能网络服务的关键技术。
文件I/O
Lua提供了一套文件I/O函数,你可以使用这些函数来读写文件。
-- 写文件
local file = io.open("test.txt", "w")
file:write("Hello, OpenResty")
file:close()
-- 读文件
local file = io.open("test.txt", "r")
local content = file:read("*a")
file:close()
print(content) -- Hello, OpenResty
Lua和C的交互
Lua提供了一套C API,允许你在C程序中调用Lua代码,也可以在Lua代码中调用C函数。这使得Lua可以很好地和C程序进行交互。
// C程序
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
int main() {
lua_State *L = luaL_newstate(); // 创建Lua状态机
luaL_openlibs(L); // 打开Lua标准库
luaL_dofile(L, "test.lua"); // 执行Lua脚本
lua_close(L); // 关闭Lua状态机
return 0;
}
-- test.lua
print("Hello, OpenResty")
Lua中的面向对象编程
虽然Lua本身并不直接支持面向对象编程,但是你可以使用表和元表来模拟类和对象。
local Person = {}
Person.__index = Person
function Person.new(name, age)
local self = setmetatable({}, Person)
self.name = name
self.age = age
return self
end
function Person:sayHello()
print("Hello, my name is " .. self.name)
end
local p = Person.new("OpenResty", 10)
p:sayHello() -- Hello, my name is OpenResty
Lua中的函数式编程
Lua支持一等函数和闭包,这使得你可以在Lua中进行函数式编程。
function add(x)
return function(y)
return x + y
end
end
local add10 = add(10)
print(add10(20)) -- 30