OpenResty之Lua语法学习
前言
OpenResty,开源作者章亦春,这个开源 Web 平台主要由章亦春(agentzh)维护。在 2011年之前曾由淘宝网赞助,在后来的 2012 - 2016 年间主要由美国的 CloudFlare 公司 提供支持。目前,OpenResty® 主要由 OpenResty 软件基金会和 OpenResty Inc. 公司提供支持。
根据作者早期描述OpenResty最早是顺应OpenAPI的潮流做的,所以 Open 取自“开放”之意,而Resty便是 REST 风格的意思。虽然后来也可以基于ngx_openresty实现任何形式的 webservice 或者传统的 web 应用。OpenResty (也称为 ngx_openresty)是一个全功能的 Web 应用服务器。它打包了标准的Nginx 核心,很多的常用的第三方模块,以及它们的大多数依赖项。
通过众多 进行良好设计的 Nginx 模块,OpenResty 有效地把 Nginx 服务器转变为一个强大的 Web 应用服务器,基于它开发人员可以使用 Lua 编程语言对 Nginx 核心以及现有的各种
Nginx C 模块进行脚本编程,构建出可以处理一万以上并发请求的极端高性能的 Web 应用。OpenResty 致力于将你的服务器端应用完全运行于 Nginx 服务器中,充分利用 Nginx 的事件模型来进行非阻塞 I/O 通信。不仅仅是和 HTTP 客户端间的网络通信是非阻塞的,与MySQL、PostgreSQL、Memcached、以及 Redis 等众多远方后端之间的网络通信也是非阻塞的。因为 OpenResty 软件包的维护者也是其中打包的许多 Nginx 模块的作者,所以 OpenResty可以确保所包含的所有组件可以可靠地协同工作。
Lua
在正式使用OpenResty之前,需要先学习一下Lua语言。
Lua 基于C语言,小巧,快速,编译后仅仅一百余K,可以很方便的嵌入别的程序里,而且它的语言与C语言工作者来说极其友好,继承于C,同时也意味着它是面向过程的语言。说明:下面的代码例子全是在Lua命令行中运行的,不是SciTE,本文代码部分的 // 实际应为 --。
1.注释
// 注释和 C 语言不同,这里是用 --
--[[
多行注释
多行注释
--]]
// 在默认情况下,变量总是认为是全局的。
b=10
print(b)
// 打印:10
2.关键词
and、break、do、else、elseif、end、false、for、function、if
in、local、nil、not、or、repeat、return、then、true、until、while
3.Lua数据类型
Lua是动态类型语言,变量不要类型定义,只需要为变量赋值。
- nil,表示一个无效值(在条件表达式中相当于false)
- boolean,跟其它语言一样,false 和 true
- number,表示双精度类型的实浮点数
- string,字符串类型
- function,由 C 或 Lua 编写的函数
- userdata,表示任意存储在变量中的C数据结构
- thread,表示执行的独立线路,用于执行协同程序
- table,表,也是一个"关联数组",类似数组但是有很多不同,组的索引可以是数字或者是字符串
print(type("Hello world")) // string
print(type(10.4*3)) // number
print(type(print)) // function
print(type(type)) // function
print(type(true)) // boolean
print(type(nil)) // nil
print(type(type(X))) // string
nil 类型表示一种没有任何有效值,它只有一个值 – nil,例如打印一个没有赋值的变量,便会输出一个 nil 值:
print(type(a))
// 运行结果:nil
boolean 类型和其他语言一样,只有两个可选值:true(真) 和 false(假),其中Lua 把 false 和 nil 看作是"假",其他的都为"真":
print(type(true))
print(type(false))
print(type(nil))
if false or nil then
print("至少有一个是 true")
else
print("false 和 nil 都为 false!")
end
// 运行结果
boolean
boolean
nil
false 和 nil 都为 false!
Lua 默认只有一种 number 类型 – double(双精度)类型(默认类型可以修改 luaconf.h 里的定义),以下几种写法都被看作是 number 类型:
print(type(2))
print(type(2.2))
print(type(0.2))
print(type(2e+1))
print(type(0.2e-1))
print(type(7.8263692594256e-06))
// 运行结果
number
number
number
number
number
number
字符串由一对双引号或单引号来表示,也可以用 2 个方括号 “[[]]” 来表示"一块"字符串。
// 测试 1string1 = "this is string1"
string2 = 'this is string2'
print(string1)
// 运行结果:
this is string1
// 测试 2html = [[
<html>
<head></head>
<body>
<div id="test">Lua测试</div>
</body>
</html>
]]
print(html)
// 运行结果
<html>
<head></head>
<body>
<div id="test">Lua测试</div>
</body>
</html>
在对一个数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字:
print("2" + 6)
// 结果:8.0
print("2" + "6")
// 结果:8.0
print("2 + 6")
// 结果:2 + 6
print("-2e2" * "6")
// 结果:-1200.0
print("error" + 1)
// 结果:stdin:1: attempt to perform arithmetic on a string value
stack traceback:
stdin:1: in main chunk
[C]: in ?
print("a" .. 'b')
// 结果:ab
print(157 .. 428)
// 结果:157428
使用 # 来计算字符串的长度,放在字符串前面,如下实例:
len = "www.lua.org"
print(#len)
// 结果:11
print(#"www.lua.org")
// 结果:11
在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。也可以在表里添加一些数据,直接初始化表:
// 创建一个空的 table
local tbl1 = {}
// 直接初始化表 local tbl2 = {"apple", "pear", "orange", "grape"}
// 表的索引初始化是1,不是0
local tbl = {"apple", "pear", "orange", "grape"}
for key, val in pairs(tbl) do
print("Key", key)
end
// 运行结果: Key 1
Key 2
Key 3
Key 4
// table 不会固定长度大小,有新数据添加时 table 长度会自动增长,
// 没初始的 table 都是 nil。
a3 = {}
for i = 1, 10 do
a3[i] = i
end
a3["key"] = "val"
print(a3["key"])
print(a3["none"])
// 运行结果: val
nil
在 Lua 中,函数是被看作是"第一类值(First-Class Value)",函数可以存在变量里:
function factorial1(n)
if n == 0 then
return 1
else
return n * factorial1(n - 1)
end
end
print(factorial1(5))
factorial2 = factorial1
print(factorial2(5))
// 运行结果: 120
120
// function 可以以匿名函数(anonymous function)的方式通过参数传递:
function testFun(tab,fun)
for k ,v in pairs(tab) do
print(fun(k,v));
end
end
tab={key1="val1",key2="val2"};
testFun(tab,
function(key,val)--匿名函数
return key.."="..val;
end
);
// 运行结果: key1 = val1
key2 = val2
在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局