1. Lua语言简介
1.1 什么是Lua
Lua是一种轻量级、高级的动态编程语言,专为嵌入应用程序而设计。在OpenResty中,Lua作为脚本语言提供了强大的可编程能力,使得我们可以在Nginx中实现复杂的业务逻辑。
1.2 Lua的特点
- 轻量级:核心库小于200KB
- 高性能:通过LuaJIT实现接近C语言的性能
- 可嵌入:易于集成到其他应用程序中
- 动态类型:运行时确定变量类型
- 垃圾回收:自动内存管理
- 协程支持:内置协程机制
1.3 在OpenResty中的作用
- 请求处理逻辑
- 数据处理和转换
- 外部服务调用
- 缓存操作
- 认证和授权
2. 基本语法
2.1 注释
-- 单行注释
--[[
多行注释
可以跨越多行
--]]
--[=[
嵌套多行注释
--[[
内部注释
--]]
--]=]
2.2 变量和标识符
-- 变量声明(全局变量)
name = "OpenResty"
age = 10
-- 局部变量
local local_name = "Local Variable"
local local_age = 5
-- 多重赋值
local a, b, c = 1, 2, 3
local x, y = 10 -- y为nil
-- 变量交换
a, b = b, a
2.3 数据类型
-- nil(空值)
local empty_var = nil
-- boolean(布尔值)
local is_true = true
local is_false = false
-- number(数字)
local integer = 42
local float = 3.14159
local scientific = 1.23e-4
-- string(字符串)
local str1 = "Hello"
local str2 = 'World'
local str3 = [[多行
字符串]]
-- table(表)
local array = {1, 2, 3, 4, 5}
local dict = {name = "OpenResty", version = "1.21"}
-- function(函数)
local func = function(x) return x * 2 end
-- userdata(用户数据)
-- thread(线程/协程)
2.4 类型检查
local value = "Hello"
print(type(value)) -- string
value = 42
print(type(value)) -- number
value = {1, 2, 3}
print(type(value)) -- table
3. 运算符
3.1 算术运算符
local a, b = 10, 3
print(a + b) -- 13 (加法)
print(a - b) -- 7 (减法)
print(a * b) -- 30 (乘法)
print(a / b) -- 3.333... (除法)
print(a % b) -- 1 (取模)
print(a ^ b) -- 1000 (幂运算)
print(-a) -- -10 (负号)
3.2 关系运算符
local a, b = 10, 5
print(a == b) -- false (等于)
print(a ~= b) -- true (不等于)
print(a > b) -- true (大于)
print(a < b) -- false (小于)
print(a >= b) -- true (大于等于)
print(a <= b) -- false (小于等于)
3.3 逻辑运算符
local a, b = true, false
print(a and b) -- false (逻辑与)
print(a or b) -- true (逻辑或)
print(not a) -- false (逻辑非)
-- 短路求值
local result = a and "true value" or "false value"
print(result) -- "true value"
3.4 其他运算符
-- 字符串连接
local str = "Hello" .. " " .. "World"
print(str) -- "Hello World"
-- 长度运算符
local arr = {1, 2, 3, 4, 5}
print(#arr) -- 5
local str = "Hello"
print(#str) -- 5
4. 控制结构
4.1 条件语句
-- if语句
local score = 85
if score >= 90 then
print("优秀")
elseif score >= 80 then
print("良好")
elseif score >= 60 then
print("及格")
else
print("不及格")
end
-- 三元运算符模拟
local result = score >= 60 and "及格" or "不及格"
print(result)
4.2 循环语句
-- while循环
local i = 1
while i <= 5 do
print("while: " .. i)
i = i + 1
end
-- repeat-until循环
local j = 1
repeat
print("repeat: " .. j)
j = j + 1
until j > 5
-- for数值循环
for k = 1, 5 do
print("for: " .. k)
end
-- for步长循环
for k = 1, 10, 2 do
print("step: " .. k) -- 1, 3, 5, 7, 9
end
-- for泛型循环
local arr = {"a", "b", "c"}
for index, value in ipairs(arr) do
print(index, value)
end
local dict = {name = "OpenResty", version = "1.21"}
for key, value in pairs(dict) do
print(key, value)
end
4.3 跳转语句
-- break语句
for i = 1, 10 do
if i == 5 then
break
end
print(i)
end
-- goto语句(Lua 5.2+)
for i = 1, 10 do
if i == 5 then
goto continue
end
print(i)
::continue::
end
5. 函数
5.1 函数定义
-- 基本函数定义
function greet(name)
return "Hello, " .. name
end
-- 匿名函数
local add = function(a, b)
return a + b
end
-- 局部函数
local function multiply(a, b)
return a * b
end
-- 调用函数
print(greet("OpenResty")) -- Hello, OpenResty
print(add(3, 4)) -- 7
print(multiply(5, 6)) -- 30
5.2 多返回值
function get_name_age()
return "Alice", 25
end
-- 接收多个返回值
local name, age = get_name_age()
print(name, age) -- Alice 25
-- 只接收第一个返回值
local first = get_name_age()
print(first) -- Alice
5.3 可变参数
function sum(...)
local args = {...}
local total = 0
for i = 1, #args do
total = total + args[i]
end
return total
end
print(sum(1, 2, 3, 4, 5)) -- 15
-- 使用select函数
function print_args(...)
local n = select('#', ...)
for i = 1, n do
local arg = select(i, ...)
print("Arg " .. i .. ": " .. tostring(arg))
end
end
print_args("a", "b", "c")
5.4 闭包
function create_counter()
local count = 0
return function()
count = count + 1
return count
end
end
local counter1 = create_counter()
local counter2 = create_counter()
print(counter1()) -- 1
print(counter1()) -- 2
print(counter2()) -- 1
print(counter1()) -- 3
6. 表(Table)
6.1 表的创建
-- 空表
local empty_table = {}
-- 数组风格
local array = {"apple", "banana", "orange"}
-- 字典风格
local person = {
name = "Alice",
age = 30,
city = "Beijing"
}
-- 混合风格
local mixed = {
"first",
"second",
name = "mixed table",
["key with spaces"] = "value"
}
6.2 表的访问
local person = {name = "Alice", age = 30}
-- 点号访问
print(person.name) -- Alice
-- 方括号访问
print(person["age"]) -- 30
-- 动态键访问
local key = "name"
print(person[key]) -- Alice
-- 数组访问
local arr = {10, 20, 30}
print(arr[1]) -- 10 (Lua数组从1开始)
print(arr[2]) -- 20
6.3 表的修改
local person = {name = "Alice"}
-- 添加新字段
person.age = 30
person["city"] = "Beijing"
-- 修改现有字段
person.name = "Bob"
-- 删除字段
person.age = nil
print(person.name) -- Bob
print(person.age) -- nil
print(person.city) -- Beijing
6.4 表的遍历
local person = {name = "Alice", age = 30, city = "Beijing"}
-- pairs遍历所有键值对
for key, value in pairs(person) do
print(key, value)
end
-- ipairs遍历数组部分
local arr = {"a", "b", "c"}
for index, value in ipairs(arr) do
print(index, value)
end
-- 数值for循环遍历数组
for i = 1, #arr do
print(i, arr[i])
end
7. 字符串处理
7.1 字符串基本操作
local str = "Hello, OpenResty!"
-- 字符串长度
print(#str) -- 17
print(string.len(str)) -- 17
-- 字符串连接
local new_str = str .. " Welcome!"
print(new_str)
-- 字符串重复
local repeated = string.rep("Ha", 3)
print(repeated) -- HaHaHa
7.2 字符串查找和替换
local text = "Hello, World! Hello, Lua!"
-- 查找子字符串
local start, end_pos = string.find(text, "World")
print(start, end_pos) -- 8 12
-- 模式匹配
local match = string.match(text, "H(%w+)")
print(match) -- ello
-- 全局匹配
for word in string.gmatch(text, "%w+") do
print(word)
end
-- 字符串替换
local new_text = string.gsub(text, "Hello", "Hi")
print(new_text) -- Hi, World! Hi, Lua!
7.3 字符串格式化
-- 格式化字符串
local name = "Alice"
local age = 30
local formatted = string.format("Name: %s, Age: %d", name, age)
print(formatted) -- Name: Alice, Age: 30
-- 数字格式化
local pi = 3.14159
print(string.format("%.2f", pi)) -- 3.14
print(string.format("%08.2f", pi)) -- 00003.14
7.4 字符串转换
-- 大小写转换
local text = "Hello World"
print(string.upper(text)) -- HELLO WORLD
print(string.lower(text)) -- hello world
-- 字符串反转
print(string.reverse(text)) -- dlroW olleH
-- 子字符串
print(string.sub(text, 1, 5)) -- Hello
print(string.sub(text, 7)) -- World
print(string.sub(text, -5)) -- World
8. 错误处理
8.1 pcall和xpcall
-- pcall保护调用
function risky_function(x)
if x == 0 then
error("Division by zero!")
end
return 10 / x
end
-- 使用pcall
local success, result = pcall(risky_function, 5)
if success then
print("Result: " .. result) -- Result: 2
else
print("Error: " .. result)
end
-- 错误情况
local success, result = pcall(risky_function, 0)
if success then
print("Result: " .. result)
else
print("Error: " .. result) -- Error: Division by zero!
end
8.2 自定义错误处理
-- 错误处理函数
function error_handler(err)
return "Custom error: " .. tostring(err)
end
-- 使用xpcall
local success, result = xpcall(risky_function, error_handler, 0)
if not success then
print(result) -- Custom error: Division by zero!
end
9. 模块和包
9.1 创建模块
-- math_utils.lua
local M = {}
function M.add(a, b)
return a + b
end
function M.multiply(a, b)
return a * b
end
M.PI = 3.14159
return M
9.2 使用模块
-- 加载模块
local math_utils = require("math_utils")
-- 使用模块函数
print(math_utils.add(3, 4)) -- 7
print(math_utils.multiply(5, 6)) -- 30
print(math_utils.PI) -- 3.14159
10. 协程(Coroutine)
10.1 协程基础
-- 创建协程
local co = coroutine.create(function()
for i = 1, 3 do
print("Coroutine: " .. i)
coroutine.yield()
end
end)
-- 运行协程
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- Coroutine: 1
print(coroutine.status(co)) -- suspended
coroutine.resume(co) -- Coroutine: 2
coroutine.resume(co) -- Coroutine: 3
print(coroutine.status(co)) -- dead
10.2 协程通信
local co = coroutine.create(function(a, b)
print("Received:", a, b)
local x, y = coroutine.yield(a + b)
print("Received:", x, y)
return x * y
end)
local success, result = coroutine.resume(co, 10, 20)
print("Yielded:", result) -- Yielded: 30
local success, result = coroutine.resume(co, 5, 6)
print("Returned:", result) -- Returned: 30
11. 在OpenResty中的应用
11.1 基本示例
-- 在nginx.conf中
location /lua-demo {
content_by_lua_block {
local name = ngx.var.arg_name or "World"
ngx.say("Hello, " .. name .. "!")
local data = {
message = "Welcome to OpenResty",
timestamp = ngx.time(),
user = name
}
ngx.header.content_type = "application/json"
ngx.say(require("cjson").encode(data))
}
}
11.2 实用函数
-- 工具函数模块
local _M = {}
-- 生成随机字符串
function _M.random_string(length)
local chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
local result = {}
for i = 1, length do
local index = math.random(1, #chars)
result[i] = string.sub(chars, index, index)
end
return table.concat(result)
end
-- 验证邮箱格式
function _M.is_valid_email(email)
local pattern = "^[%w%._%+%-]+@[%w%._%+%-]+%.%w+$"
return string.match(email, pattern) ~= nil
end
-- 深拷贝表
function _M.deep_copy(orig)
local copy
if type(orig) == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[_M.deep_copy(orig_key)] = _M.deep_copy(orig_value)
end
setmetatable(copy, _M.deep_copy(getmetatable(orig)))
else
copy = orig
end
return copy
end
return _M
12. 总结
Lua作为OpenResty的核心脚本语言,提供了强大而灵活的编程能力。掌握Lua的基础语法、数据类型、控制结构、函数、表操作等核心概念,是深入学习OpenResty的重要基础。通过本章的学习,我们为后续的OpenResty开发打下了坚实的语言基础。