目录
什么是 Lua?
Lua 环境安装
Lua基本语法
注释
数据类型
nil(空)
Boolean
number(数字)
string(字符串)
function(函数)
userdata
thread
table(表)
流程控制
运算符
循环
详解string库
Lua 模块与包
案例实战
什么是 Lua?
Lua 是一种轻量小巧的脚本语言,它用标准C语言编写并以源代码形式开放。这意味着什么呢?这意味着Lua虚拟机可以很方便的嵌入别的程序里,从而为应用程序提供灵活的扩展和定制功能。而整个Lua虚拟机编译后仅仅一百余K,经过适当的裁剪还能做到更小,十分适合嵌入式的开发。
Lua 官网:The Programming Language Lua
Lua 5.3 参考手册:Lua 5.3 参考手册 - 目录
Lua 在线调试工具:LuatOS 在线模拟 - lua在线测试
Lua 环境安装
可以不安装 Lua环境, 直接用在线调试就可以, 但也有一些学习需要安装,有需要的可以安装.
Linux 系统上安装
下载源码安装:
curl -L -R -O https://www.lua.org/ftp/lua-5.3.6.tar.gz tar zxf lua-5.3.6.tar.gz cd lua-5.3.6 make all test make install
Window 系统上安装 Lua
window 下你可以使用一个叫 "SciTE" 的 IDE环 境来执行 lua 程序,下载地址为:
-
Github 下载地址:https://github.com/rjpcomputing/luaforwindows/releases
-
Google Code下载地址 : https://code.google.com/p/luaforwindows/downloads/list
双击安装后即可在该环境下编写 Lua 程序并运行。
或者
访问Lua Binaries Download 下载
把红圈内的东西,下载后解压到c:\lua(里面有dll文件重复了,取可执行文件包内的就行了)
c:\lua目录情况如下
直接运行lua53.exe 就可以
Lua基本语法
以下大部分的 Lua 语句都在Lua在线调试工具上执行。
注释
单行注释
单行注释以两个连字符 --
开头,后面跟随的内容将被解释器忽略。
--
单行注释通常用于对代码的简短解释或标记。
多行注释
多行注释以 --[[
开始,并以 ]]
结束,适用于需要对大段代码进行说明的情况。
--[[ 多行注释 多行注释 --]]
Lua 不支持嵌套注释,这意味着在一个多行注释内不能再嵌套另一个多行注释。
数据类型
Lua 是动态类型语言,变量不要类型定义,只需要为变量赋值。 值可以存储在变量中,作为参数传递或结果返回。
Lua 中有 8 个基本类型分别为:nil、boolean、number、string、userdata、function、thread 和 table。
类型 | 描述 |
---|---|
nil | 这个最简单,只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。 |
boolean | 包含两个值:false和true。 |
number | 表示双精度类型的实浮点数 |
string | 字符串由一对双引号或单引号来表示 |
function | 由 C 或 Lua 编写的函数 |
userdata | 表示任意存储在变量中的C数据结构 |
thread | 表示执行的独立线路,用于执行协同程序 |
table | Lua 中的表(table)其实是一个"关联数组"(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。 |
-
nil(空)
Nil 是值 nil 的类型, 其主要特征就是和其它值区别开;通常用来表示一个有意义的值不存在时的状态。例如打印一个没有赋值的变量,便会输出一个 nil 值:
在lua在线测试 上执行命令
print(a)
运行结果
-
Boolean
Boolean 是 false 与 true 两个值的类型。 nil 和 false 都会导致条件判断为假; 而其它任何值都表示为真,数字 0 也是 true。
print(type(true))
print(type(false))
print(type(nil))
if false or nil then
print("至少有一个是 true")
else
print("false 和 nil 都为 false")
end
if 0 then
print("数字 0 是 true")
else
print("数字 0 为 false")
end
以上代码执行结果如下:
$ lua test.lua
boolean
boolean
nil
false 和 nil 都为 false
数字 0 是 true
-
number(数字)
Number 代表了整数和实数(浮点数),也就是double(双精度)类型。
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
-
string(字符串)
字符串
(即string
),就是一串文本数据,可以存储你要的文本。
Lua 语言中字符串可以使用以下三种方式来表示:
-
单引号间的一串字符
-
双引号间的一串字符
-
[[和]]间的一串字符
string1 = "this is string1"
string2 = 'this is string2'
str4 = [[使用双括号时,甚至能包含换行数据
换行了
最后一行]]
print(string1)
print(string2)
print(str4)
以上代码执行结果:
this is string1
this is string2
使用双括号时,甚至能包含换行数据
换行了
最后一行
-
function(函数)
在Lua中,函数是对语句和表达式进行抽象的主要方法。既可以用来处理一些特殊的工作,也可以用来计算一些值。
Lua 提供了许多的内建函数,你可以很方便的在程序中调用它们,如print()函数可以将传入的参数打印在控制台上。
Lua 函数主要有两种用途:
- 1.完成指定的任务,这种情况下函数作为调用语句使用;
- 2.计算并返回值,这种情况下函数作为赋值语句的表达式使用。
函数定义
Lua 编程语言函数定义格式如下:
optional_function_scope function function_name( argument1, argument2, argument3..., argumentn)
function_body
return result_params_comma_separated
end
解析:
-
optional_function_scope: 该参数是可选的指定函数是全局函数还是局部函数,未设置该参数默认为全局函数,如果你需要设置函数为局部函数需要使用关键字 local,通常不设置。
-
function_name: 指定函数名称。
-
argument1, argument2, argument3..., argumentn: 函数参数,多个参数以逗号隔开,函数也可以不带参数。
-
function_body: 函数体,函数中需要执行的代码语句块。
-
result_params_comma_separated: 函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开。
定义如下:
function hello()
print('Hello world!')
end
-- 调用函数
hello()
定义传参,只需写参数名称,不需要写参数类型,比如:argument1, argument2
function hello(argument1, argument2)
print('Hello world!',argument1, argument2)
end
-- 调用函数
hello('参数1', '参数2')
定义函数返回值,如果多个返回值,则以逗号隔开,然后接受变量多个
function hello(argument1, argument2)
print('Hello world!',argument1, argument2)
return argument1,argument2
end
-- 调用函数
val1,val2=hello('参数1', '参数2')
print(val1,val2)
可变参数
Lua 函数可以接受可变数目的参数,和 C 语言类似,在函数参数列表中使用三点 ... 表示函数有可变的参数。
function hello(...)
local arg={...}
return arg
end
-- 调用函数
arr=hello('参数1', '参数2','参数3')
print(arr[1],arr[2],arr[3])
-
userdata
userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。
用户数据类型的值是一个内存块, 有两种用户数据: 完全用户数据 ,指一块由 Lua 管理的内存对应的对象; 轻量用户数据 ,则指一个简单的 C 指针。 用户数据在 Lua 中除了赋值与相等性判断之外没有其他预定义的操作。
-
thread
thread 类型表示了一个独立的执行序列,被用于实现协程 。 Lua 的线程与操作系统的线程毫无关系。 Lua 为所有的系统,包括那些不支持原生线程的系统,提供了协程支持。
在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。
线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。
基本语法
协同程序由 coroutine 模块提供支持。
使用协同程序,你可以在函数中使用 coroutine.create 创建一个新的协同程序对象,并使用 coroutine.resume 启动它的执行。协同程序可以通过调用 coroutine.yield 来主动暂停自己的执行,并将控制权交还给调用者。
方法 | 描述 |
---|---|
coroutine.create() | 创建 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用 |
coroutine.resume() | 重启 coroutine,和 create 配合使用 |
coroutine.yield() | 挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果 |
coroutine.status() | 查看 coroutine 的状态 注:coroutine 的状态有三种:dead,suspended,running,具体什么时候有这样的状态请参考下面的程序 |
coroutine.wrap() | 创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复 |
coroutine.running() | 返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 coroutine 的线程号 |
以下实例演示了如何使用 Lua 协同程序:
function foo()
print("协同程序 foo 开始执行")
local value = coroutine.yield("暂停 foo 的执行")
print("协同程序 foo 恢复执行,传入的值为: " .. tostring(value))
print("协同程序 foo 结束执行")
end
-- 创建协同程序
local co = coroutine.create(foo)
-- 启动协同程序
local status, result = coroutine.resume(co)
print(result) -- 输出: 暂停 foo 的执行
-- 恢复协同程序的执行,并传入一个值
status, result = coroutine.resume(co, 42)
print(result) -- 输出: 协同程序 foo 恢复执行,传入的值为: 42
以上实例中,我们定义了一个名为 foo 的函数作为协同程序。在函数中,我们使用 coroutine.yield 暂停了协同程序的执行,并返回了一个值
。在主程序中,我们使用 coroutine.create 创建了一个协同程序对象,并使用 coroutine.resume 启动了它的执行。
在第一次调用 coroutine.resume 后,协同程序执行到 coroutine.yield 处暂停,并将值返回给主程序。然后,我们再次调用 coroutine.resume,并传入一个值作为协同程序恢复执行时的参数。
执行以上代码输出结果为:
协同程序 foo 开始执行 暂停 foo 的执行 协同程序 foo 恢复执行,传入的值为: 42 协同程序 foo 结束执行 nil
-
table(表)
在 Lua 里,table 的创建是通过"构造表达式"来完成,最简单构造表达式是{},用来创建一个空表。也可以在表里添加一些数据,直接初始化表:
-- 创建一个空的 table
local tbl1 = {}
-- 直接初始表
local tbl2 = {"apple", "pear", "orange", "grape"}
我们甚至能在里面放function
变量
t = {
function() return 123 end,
function() print("abc") end,
function(a,b) return a+b end,
function() print("hello world") end,
}
t[1]()
t[2]()
t[3](1,2)
t[4]()
这些table
访问每个元素的方式仍然是直接用下标,并且也能用下标来进行修改。
下标也可以直接在声明时进行指定,像下面这样:
t = {6,7,8,9}
--上面和下面的代码等价
t = {
[1] = 6,
[2] = 7,
[3] = 8,
[4] = 9,
}
--甚至你可以跳过某些下标
t = {
[1] = 6,
[3] = 7,
[5] = 8,
[7] = 9,
}
print(t[7])
--输出9
--在声明后赋予元素值也是可以的
t = {}--空的table
t[101] = 10
print(t[101])
--输出10
在Lua中,下标也可以是字符串,如下面的例子
t = {
["apple"] = 10,
banana = 12,
pear = 6,
}
--使用["下标"] = 值
--和 下标 = 值
--都是正确写法
--当第二种方式有歧义时,应该用第一种方式
--可以用下面两种方式访问:
print(t["apple"])
--输出10
print(t.apple)
--输出10
--当第二种方式有歧义时,应该用第一种方式
在table
中,可以直接用table名[下标]
或table名.string下标
来访问元素。实际上,在Lua中,所有的全局变量全部被存放在了一个大table
中,这个table
名为:_G
n = 123--新建变量
print(n)--输出123
print(_G.n)--输出123
_G.abc = 1--相当于新建全局变量
print(abc)--输出1
_G["def"] = 23--相当于新建全局变量
print(def)--输出23
--甚至你可以像下面这样
_G.print("hello")
_G["print"]("world")
Table 操作
以下列出了 Table 操作常用的方法:
序号 | 方法 & 用途 |
---|---|
1 | table.concat (table [, sep [, start [, end]]]): concat是concatenate(连锁, 连接)的缩写. table.concat()函数列出参数中指定table的数组部分从start位置到end位置的所有元素, 元素间以指定的分隔符(sep)隔开。 |
2 | table.insert (table, [pos,] value): 在table的数组部分指定位置(pos)插入值为value的一个元素. pos参数可选, 默认为数组部分末尾. |
3 | table.maxn (table) 指定table中所有正数key值中最大的key值. 如果不存在key值为正数的元素, 则返回0。(Lua5.2之后该方法已经不存在了,本文使用了自定义函数实现) |
4 | table.remove (table [, pos]) 返回table数组部分位于pos位置的元素. 其后的元素会被前移. pos参数可选, 默认为table长度, 即从最后一个元素删起。 |
5 | table.sort (table [, comp]) 对给定的table进行升序排序。 |
Table 连接
我们可以使用 concat() 输出一个列表中元素连接成的字符串:
实例
fruits = {"banana","orange","apple"}
-- 返回 table 连接后的字符串
print("连接后的字符串 ",table.concat(fruits))
-- 指定连接字符
print("连接后的字符串 ",table.concat(fruits,", "))
-- 指定索引来连接 table
print("连接后的字符串 ",table.concat(fruits,", ", 2,3))
执行以上代码输出结果为:
连接后的字符串 bananaorangeapple 连接后的字符串 banana, orange, apple 连接后的字符串 orange, apple
插入和移除
以下实例演示了 table 的插入和移除操作:
实例
fruits = {"banana","orange","apple"}
-- 在末尾插入
table.insert(fruits,"mango")
print("索引为 4 的元素为 ",fruits[4])
-- 在索引为 2 的键处插入
table.insert(fruits,2,"grapes")
print("索引为 2 的元素为 ",fruits[2])
print("最后一个元素为 ",fruits[5])
table.remove(fruits)
print("移除后最后一个元素为 ",fruits[5])
执行以上代码输出结果为:
索引为 4 的元素为 mango 索引为 2 的元素为 grapes 最后一个元素为 mango 移除后最后一个元素为 nil
Table 排序
以下实例演示了 sort() 方法的使用,用于对 Table 进行排序:
实例
fruits = {"banana","orange","apple","grapes"}
print("排序前")
for k,v in ipairs(fruits) do
print(k,v)
end
table.sort(fruits)
print("排序后")
for k,v in ipairs(fruits) do
print(k,v)
end
执行以上代码输出结果为:
排序前 1 banana 2 orange 3 apple 4 grapes 排序后 1 apple 2 banana 3 grapes 4 orange
Table 最大值
table.maxn 在 Lua5.2 之后该方法已经不存在了,我们定义了 table_maxn 方法来实现。
以下实例演示了如何获取 table 中的最大值:
实例
function table_maxn(t)
local mn=nil;
for k, v in pairs(t) do
if(mn==nil) then
mn=v
end
if mn < v then
mn = v
end
end
return mn
end
tbl = {[1] = 2, [2] = 6, [3] = 34, [26] =5}
print("tbl 最大值:", table_maxn(tbl))
print("tbl 长度 ", #tbl)
执行以上代码输出结果为:
tbl 最大值: 34 tbl 长度 3
注意:
当我们获取 table 的长度的时候无论是使用 # 还是 table.getn 其都会在索引中断的地方停止计数,而导致无法正确取得 table 的长度。
可以使用以下方法来代替:
function table_leng(t)
local leng=0
for k, v in pairs(t) do
leng=leng+1
end
return leng;
end
流程控制
Lua 提供了以下控制结构语句:
语句 | 描述 |
---|---|
if 语句 | if 语句 由一个布尔表达式作为条件判断,其后紧跟其他语句组成。 |
if...else 语句 | if 语句 可以与 else 语句搭配使用, 在 if 条件表达式为 false 时执行 else 语句代码。 |
if 嵌套语句 | 你可以在if 或 else if中使用一个或多个 if 或 else if 语句 。 |
单条件判断
if 条件 then
符合条件的代码
end
实例
n = 5
if n < 10 then
print('n小于10')
end
多条件判断
if 条件1 then
满足条件1
elseif 条件2 then
不满足条件1,但是满足条件2
else
前面条件全都不满足
end
实例
n = 1--更改这个数多运行几次试试
if n >= 0 and n < 5 then
print('太小')
elseif n >= 5 and n < 10 then
print('适中')
elseif n >= 10 then
print('太大')
end
运算符
运算符是一个特殊的符号,用于告诉解释器执行特定的数学或逻辑运算。Lua提供了以下几种运算符类型:
- 算术运算符
- 关系运算符
- 逻辑运算符
- 其他运算符
算术运算符
下表列出了 Lua 语言中的常用算术运算符,设定 A 的值为10,B 的值为 20:
操作符 | 描述 | 实例 |
---|---|---|
+ | 加法 | A + B 输出结果 30 |
- | 减法 | A - B 输出结果 -10 |
* | 乘法 | A * B 输出结果 200 |
/ | 除法 | B / A 输出结果 2 |
% | 取余 | B % A 输出结果 0 |
^ | 乘幂 | A^2 输出结果 100 |
- | 负号 | -A 输出结果 -10 |
// | 整除运算符(>=lua5.3) | 5//2 输出结果 2 |
实例
我们可以通过以下实例来更加透彻的理解算术运算符的应用:
实例
a = 21
b = 10
c = a + b
print("Line 1 - c 的值为 ", c )
c = a - b
print("Line 2 - c 的值为 ", c )
c = a * b
print("Line 3 - c 的值为 ", c )
c = a / b
print("Line 4 - c 的值为 ", c )
c = a % b
print("Line 5 - c 的值为 ", c )
c = a^2
print("Line 6 - c 的值为 ", c )
c = -a
print("Line 7 - c 的值为 ", c )
以上程序执行结果为:
Line 1 - c 的值为 31 Line 2 - c 的值为 11 Line 3 - c 的值为 210 Line 4 - c 的值为 2.1 Line 5 - c 的值为 1 Line 6 - c 的值为 441 Line 7 - c 的值为 -21
关系运算符
下表列出了 Lua 语言中的常用关系运算符,设定 A 的值为21,B 的值为 10:
操作符 | 描述 | 实例 |
---|---|---|
== | 等于,检测两个值是否相等,相等返回 true,否则返回 false | (A == B) 为 false。 |
~= | 不等于,检测两个值是否相等,不相等返回 true,否则返回 false | (A ~= B) 为 true。 |
> | 大于,如果左边的值大于右边的值,返回 true,否则返回 false | (A > B) 为 false。 |
< | 小于,如果左边的值大于右边的值,返回 false,否则返回 true | (A < B) 为 true。 |
>= | 大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false | (A >= B) 返回 false。 |
<= | 小于等于, 如果左边的值小于等于右边的值,返回 true,否则返回 false | (A <= B) 返回 true。 |
实例
a = 21
b = 10
print('==的结果',a==b)
print('~=的结果',a~=b)
print('>的结果',a>b)
print('<的结果',a<b)
print('>=的结果',a>=b)
print('<=的结果',a<=b)
执行以上代码输出结果为:
==的结果 false
~=的结果 true
>的结果 true
<的结果 false
>=的结果 true
<=的结果 false
逻辑运算符
逻辑运算符基于布尔型的值来进行计算,并给出结果,下表列出了 Lua 语言中的常用逻辑运算符:
符号 | 含义 |
---|---|
and | 逻辑与操作符。 若 A 为 false,则返回 A,否则返回 B |
or | 逻辑或操作符。 若 A 为 true,则返回 A,否则返回 B |
not | 逻辑非操作符。与逻辑运算结果相反,如果条件为 true,逻辑非为 false |
实例
print('true and false的结果',true and false)
print('true or false的结果',true or false)
print('true and true的结果',true and true)
print('false or false的结果',false or false)
print('not false的结果',not false)
print('123 and 345的结果',123 and 345)
print('nil and true的结果',nil and true)
执行以上代码输出结果为:
true and false的结果 false true or false的结果 true true and true的结果 true false or false的结果 false not false的结果 true 123 and 345的结果 345 nil and true的结果 nil
其他运算符
下表列出了 Lua 语言中的连接运算符与计算表或字符串长度的运算符:
操作符 | 描述 | 实例 |
---|---|---|
.. | 连接两个字符串 | a..b ,其中 a 为 "Hello " , b 为 "World", 输出结果为 "Hello World"。 |
# | 一元运算符,返回字符串或表的长度。 | #"Hello" 返回 5 |
实例
我们可以通过以下实例来更加透彻的理解连接运算符与计算表或字符串长度的运算符的应用:
实例
a = "Hello "
b = "World"
print("连接字符串 a 和 b ", a..b )
print("b 字符串长度 ",#b )
print("字符串 Test 长度 ",#"Test" )
print("菜鸟教程网址长度 ",#"www.runoob.com" )
以上程序执行结果为:
连接字符串 a 和 b Hello World b 字符串长度 5 字符串 Test 长度 4 菜鸟教程网址长度 14
循环
在实际功能实现中,经常会遇到需要循环运行的代码,比如从1到100填充table数据,我们可以直接用循环语句来实现
Lua 语言提供了以下几种循环处理方式:
循环类型 | 描述 |
---|---|
while 循环 | 在条件为 true 时,让程序重复地执行某些语句。执行语句前会先检查条件是否为 true。 |
for 循环 | 重复执行指定语句,重复次数可在 for 语句中控制。 |
repeat...until | 重复执行循环,直到 指定的条件为真时为止 |
循环嵌套 | 可以在循环内嵌套一个或多个循环语句(while do ... end;for ... do ... end;repeat ... until;) |
while 循环
while
这个循环语法,整体的格式如下:
while 继续循环判断依据 do 执行的代码 end
实例
local result = 0
local num = 1
while num <= 100 do
result = result + num
num = num + 1
end
print(result)
for 循环
for
这个循环语法,整体的格式如下:for 临时变量名=开始值,结束值,步长 do 循环的代码 end
其中,步长
可以省略,默认为1
临时变量名
可以直接在代码区域使用(但不可更改),每次循环会自动加步长值
,并且在到达结束值
后停止循环. 如果需要倒序, 则步长设置为负数就可以,比如-1,代表每次减一.
实例
local result = 0
for i=1,100 do
result = result + i
end
print(result)
中断循环
如果想跳出 while 或者 for 循环,则可以使用 break 关键字, 代码如下
result = 0
for i=1,100 do
result = result + i
if result > 100 then
result = result - i
break
end
end
print(result)
for 迭代器
在 Lua 中迭代器是一种支持指针类型的结构,它可以遍历集合的每一个元素。
泛型 for 迭代器提供了集合的 key/value 对,语法格式如下:
for k, v in pairs(t) do print(k, v) end
上面代码中,k, v为变量列表;pairs(t)为表达式列表。
查看以下实例:
实例
array = {"Google", "Runoob"}
for key,value in ipairs(array)
do
print(key, value)
end
以上代码执行输出结果为:
1 Google 2 Runoob
详解string库
Lua 提供了很多字符串操作 api,方便我们对字符串的操作,接下来讲解string库的各种接口.
序号 | 方法 & 用途 |
---|---|
1 | string.upper(argument): > print(string.upper('abcd')) ABCD |
2 | string.lower(argument): > print(string.upper('ABCD')) abcd |
3 | string.gsub(mainString,findString,replaceString,num) 在字符串中替换。 mainString 为要操作的字符串, findString 为被替换的字符,replaceString 要替换的字符,num 替换次数(可以忽略,则全部替换),如:> string.gsub("aaaa","a","z",3); zzza 3 |
4 | string.find (str, substr, [init, [plain]]) 在一个指定的目标字符串 str 中搜索指定的内容 substr,如果找到了一个匹配的子串,就会返回这个子串的起始索引和结束索引,不存在则返回 nil。 init 指定了搜索的起始位置,默认为 1,可以一个负数,表示从后往前数的字符个数。 plain 表示是否使用简单模式,默认为 false,true 只做简单的查找子串的操作,false 表示使用使用正则模式匹配。 以下实例查找字符串 "Lua" 的起始索引和结束索引位置: > string.find("Hello Lua user", "Lua", 1) 7 9 |
5 | string.reverse(arg) 字符串反转 > string.reverse("Lua") auL |
6 | string.format(...) 返回一个类似printf的格式化字符串 > string.format("the value is:%d",4) the value is:4 |
7 | string.char(arg) 和 string.byte(arg[,int]) char 将整型数字转成字符并连接, byte 转换字符为整数值(可以指定某个字符,默认第一个字符)。 > string.char(97,98,99,100) abcd > string.byte("ABCD",4) 68 > string.byte("ABCD") 65 |
8 | string.len(arg) 计算字符串长度。 string.len("abc") 3 |
9 | string.rep(string, n) 返回字符串string的n个拷贝 > string.rep("abcd",2) abcdabcd |
10 | .. 链接两个字符串 > print("www.runoob.".."com") www.runoob.com |
11 | string.gmatch(str, pattern) 返回一个迭代器函数,每一次调用这个函数,返回一个在字符串 str 找到的下一个符合 pattern 描述的子串。如果参数 pattern 描述的字符串没有找到,迭代函数返回nil。 > for word in string.gmatch("Hello Lua user", "%a+") do print(word) end Hello Lua user |
12 | string.match(str, pattern, init) string.match()只寻找源字串str中的第一个配对. 参数init可选, 指定搜寻过程的起点, 默认为1。 在成功配对时, 函数将返回配对表达式中的所有捕获结果; 如果没有设置捕获标记, 则返回整个配对字符串. 当没有成功的配对时, 返回nil。 > = string.match("I have 2 questions for you.", "%d+ %a+") 2 questions > = string.format("%d, %q", string.match("I have 2 questions for you.", "(%d+) (%a+)")) 2, "questions" |
13 | string.sub(s, i [, j]) string.sub() 用于截取字符串.返回字符串 s 中,从索引 i 到索引 j 之间的子字符串。i 可以为负数,表示倒数第几个字符。当 j 缺省时,默认为 -1,也就是字符串 s 的最后位置。当索引 i 在字符串 s 的位置在索引 j 的后面时,将返回一个空字符串。 >print(string.sub('abcdcef',2,5)) bcdc |
Lua 模块与包
模块类似于一个封装库,从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。
Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行。以下为创建自定义模块 module.lua,文件代码格式如下:
-- 文件名为 module.lua
-- 定义一个名为 module 的模块
module = {}
-- 定义一个常量
module.constant = "这是一个常量"
-- 定义一个函数
function module.func1()
io.write("这是一个公有函数!\n")
end
local function func2()
print("这是一个私有函数!")
end
function module.func3()
func2()
end
return module
由上可知,模块的结构就是一个 table 的结构,因此可以像操作调用 table 里的元素那样来操作调用模块里的常量或函数。
上面的 func2 声明为程序块的局部变量,即表示一个私有函数,因此是不能从外部访问模块里的这个私有函数,必须通过模块里的公有函数来调用.
require 函数
Lua提供了一个名为require的函数用来加载模块。要加载一个模块,只需要简单地调用就可以了。
- 运行指定文件
- 末尾不带拓展名
- 目录层级用"."分隔
- 只会运行一次
- 从package.path中的路径里查找
例如:
require("<模块名>")
或者
require "<模块名>"
执行 require 后会返回一个由模块常量或函数组成的 table,并且还会定义一个包含该 table 的全局变量。
test_module.lua 文件
-- test_module.lua 文件
-- module 模块为上文提到到 module.lua
require("module")
print(module.constant)
module.func3()
以上代码执行结果为:
这是一个常量 这是一个私有函数!
或者给加载的模块定义一个别名变量,方便调用:
test_module2.lua 文件
-- test_module2.lua 文件
-- module 模块为上文提到到 module.lua
-- 别名变量 m
local m = require("module")
print(m.constant)
m.func3()
以上代码执行结果为:
这是一个常量 这是一个私有函数!
加载机制
对于自定义的模块,模块文件不是放在哪个文件目录都行,函数 require 有它自己的文件路径加载策略,它会尝试从 Lua 文件或 C 程序库中加载模块。
require 用于搜索 Lua 文件的路径是存放在全局变量 package.path 中,当 Lua 启动后,会以环境变量 LUA_PATH 的值来初始这个环境变量。如果没有找到该环境变量,则使用一个编译时定义的默认路径来初始化。
当然,如果没有 LUA_PATH 这个环境变量,也可以自定义设置,在当前用户根目录下打开 .profile 文件(没有则创建,打开 .bashrc 文件也可以),例如把 "~/lua/" 路径加入 LUA_PATH 环境变量里:
#LUA_PATH export LUA_PATH="~/lua/?.lua;;"
文件路径以 ";" 号分隔,最后的 2 个 ";;" 表示新加的路径后面加上原来的默认路径。
接着,更新环境变量参数,使之立即生效。
source ~/.profile
这时假设 package.path 的值是:
-- 打印 package.path的 值
print(package.path)
/Users/dengjoe/lua/?.lua;./?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/share/lua/5.1/?/init.lua;/usr/local/lib/lua/5.1/?.lua;/usr/local/lib/lua/5.1/?/init.lua
那么调用 require("module") 时就会尝试打开以下文件目录去搜索目标。
/Users/dengjoe/lua/module.lua; ./module.lua /usr/local/share/lua/5.1/module.lua /usr/local/share/lua/5.1/module/init.lua /usr/local/lib/lua/5.1/module.lua /usr/local/lib/lua/5.1/module/init.lua
如果找过目标文件,则会调用 package.loadfile 来加载模块。否则,就会去找 C 程序库。
搜索的文件路径是从全局变量 package.cpath 获取,而这个变量则是通过环境变量 LUA_CPATH 来初始。
搜索的策略跟上面的一样,只不过现在换成搜索的是 so 或 dll 类型的文件。如果找得到,那么 require 就会通过 package.loadlib 来加载它。
案例实战
案例:lua 上运行 redis
第一步: Window 系统上安装 Lua(如果已安装则可忽略)
-
Github 下载地址:https://github.com/rjpcomputing/luaforwindows/releases
安装好之后,需要将 D:\software\lua\5.1\lua.exe 添加到环境变量中
第二步:Window 系统上安装 luaRocks
luaRocks 是什么?
LuaRocks 是一个用于管理 Lua 模块的包管理器。它允许用户轻松地安装、更新和管理 Lua 库和模块。通过 LuaRocks,用户可以从在线的 Lua 库仓库中下载和安装所需的模块,也可以创建自己的模块包并分享给其他用户。
下载 luaRocks
下载luaRocks,它是一个lua相关类型的维护工具包,下载地址:luarocks 下载。
安装 luaRocks
下载后从cmd命令行中运行Install.bat安装。
点击 Install.bat 之后会卡在红色框框那,直接按 Enter 键 安装完成。
第三步:从cmd 命令中安装 redis-lua 模块
luarocks install redis-lua
第四步:在lua.exe中执行以下命令.
redis = require 'redis'
-- 创建一个Redis连接对象
client = redis.connect('127.0.0.1', 6379)
-- 设置键值对
client:set('foo', 'bar')
-- 获取并打印键的值
print(client:get('foo'))
-- 关闭连接
client:close()