目录
开发环境搭建
- 安装vscode并安装Lua相关的插件
- LuaCoderAssist插件:lua函数提示、代码补全等功能
- Lua Language Server coded by Lua插件
从源码安装Lua解释器、编译器、库
环境:Ubuntu 22.04.2 LTS,lua版本:5.3.6release
- 选择一个合适的版本进行下载,这里以lua5.3为例
wget http://www.lua.org/ftp/lua-5.3.6.tar.gz
- 解压:
tar -zxvf lua-5.3.6.tar.gz
- 编译
- 进入Lua源码工程根目录下
cd lua-5.3.6/
- 编译:
make linux
,编译成功后在src目录会生成lua、luac、liblua.a。 - 如果编译时遇到如下问题,则需要使用
sudo apt install libreadline-dev
命令安装readline开发包,然后重新编译
- 验证是否编译成功:执行
make test
,如果安装成功则输出lua解释器的版本信息。 - 安装:
make linux install
注释
- 单行注释:使用两个连续的连字符
- 多行注释:使用两个连续的连字符加上两对连续方括号
1. --这是单行注释
2. --[[这是多行注释--]]
全局变量/局部变量
- Lua语言中的全局变量无需声明即可使用,使用未经初始化的全局变量得到的值为nil
print(a) --nil
a = 10
print(a) --10
--全局变量与局部变量的区别
i = 100;
function printVar()
local i = 200;
print(i) --200
end
printVar()
print(i) --100
- 局部变量:
- 局部变量使用local关键字修饰,如果一个变量不使用local关键字修饰则它是全局变量。
- 使用do程序块可以更好的控制某些局部变量的生效范围
do local x = 100; local y = 200; end -- 局部变量x和y只在do程序块生效 print(x, y); --nil nil
数据类型
八种基本类型如下:
1. 数值型(number)
2. 逻辑性(boolean)
3. 字符串类型(string)
4. 函数(function)
5. 表(table)
6. 自定义类型(userdata)
7. 线程(thread)
8. 空类型(nil)
- nil:nil这种数据类型只有一个值nil
--变量在被赋值前的默认值就是nil
print(a) --nil
local b
print(b) --nil
- boolean:Lua语言中,除了nil和false都视为true
if(0)
then
print("0也是true") --0也是true
end
if(" ")
then
print("空字符串也是true") --空字符串也是true
end
- string:使用单引号和双引号来声明string类型的字符串常量
- Lua中的字符串是不可变值
- 使用一对方括号声明多行字符串常量,例如:
a = [[ <html> <head> <title>网页标题</title> </head> <body> <a href='http://www.baidu.com'>一个a标签</a> </body> </html> ]]; print(a);
- 字符串转为数值:使用函数tonumber
print(tonumber('100')); -- 100 print(tonumber('hhh')); -- nil
- 字符串常用函数:
- string.len(s):返回字符串s的长度
- string.rep(s,n):返回字符串s重复n次的结果
- string.reverse:将字符串翻转
- string.lower:将字符串中的大写字母转为小写
- string.upper:将字符串中的小写字母转为大写字母
- string.sub:获取子串。注意字符串的第一个索引为1,索引-1代表字符串的最后一个字符
a = 'helloworld'; print(string.sub(a, 1, 1)); -- h
- string.char:接收0个或者多个整数作为参数,然后将每个整数转换为对应的字符,最后返回由这些字符连接而成的字符串
- string.byte(s,i):返回字符串s中第i个字符的内部数值表示
- string.format:字符串格式化
print(string.format("x = %f", 20));
- string.find():在指定的字符串中进行模式搜索
- string.gsub:将所有匹配的模式用另一个字符串替换
- number:在Lua中,整数和浮点数都用number数据类型来表示
--如何区分整型值和浮点数值
if(3 == 3.0)
then
print("Lua语言中,具有相同算数值的整型值和浮点值是相同的")
end
-- 使用math.type函数进行区分
print(math.type(3)) --integer
print(math.type(3.0))--float
--Lua支持十六进制的浮点数
a = 0xff;
print(a); -- 255
-- 整型值的最大值和最小值
print(math.maxinteger);
print(math.mininteger);
--将浮点型的值(表示的是整数)转化为整形
print(math.tointeger(-5.0)); -- -5
print(math.tointeger(-5.1)); -- nil
--将数值转化为字符串:使用tostring函数
- thread
- table
print(type({})) -- table
- userdata
- function
-- type函数用于获取数据类型
print(type(type)) -- function
print(type(print)) -- function
运算符
1.算术运算
- //:floor除法(整数除法),对得到的商向负无穷取整,得到整数
- %:取模运算
- ^:幂运算
2.逻辑运算
- 和:and
- 或:or
- 非:not,not运算符返回boolean类型的值
print((13 > 12) and 23) --23
print(2 < 1 or 23) --23
print(not 0) --false (0表示为true)
注意:false和nil表示false,其他的代表true
3.关系运算
关系运算的结果为Boolean类型。
- ~=:表示不等于。如果两个值的类型不同,则两者不相等
- ==:等于,如果两个值的类型不同,则两者不相等
print(nil == nil); --true
-- type函数返回一个字符串类型
print(type(nil) == nil); --false
4.长度操作符
长度操作符#:对于表格,获取表格中正整数索引的元素的长度;对于字符串,获取字符串占用的字节数。
table = {100,200,"hello"}
print(#table) --3
print(#"您好")--4,文件的编码是GBK
# 中间存在nil值的列表
a = {}
a[1] = 1
a[2] = nil
a["str"] = "hello"
a[3] = 3
print(#a) --1
--存在空洞的表
list = {1,2,3,nil,4,nil}; -- 3
print(#list);
list1 = {1,2,3,nil,4}; -- 5
print(#list1);
5.连接符
..
:进行字符串的连接。这和Java语言不一样,Java中使用+
进行字符串的连接。
a = 'hello';
b = a .. 'world';
print(b); --helloworld
控制结构
1.条件结构
- if then end
- if then else end
- if then elseif then else end
2.循环结构
- while循环:while do end
- repeat until:和while循环的区别是这个循环的循环体至少执行一次。
- for循环:
- 数值型for:格式为
for var = start,end, step do 循环体 end
-- 1 3 5 7 9 for i = 1, 10, 2 do io.write(i," "); end
- 泛型for:结合ipairs、pairs迭代器函数使用
local list = {1, 3, 5, nil, 9}; for k, v in ipairs(list) do print(k, v); end
- 数值型for:格式为
3.几个关键字
- return:结束函数的运行
- goto:将当前程序跳转到相应的标签处继续执行。使用语法为
goto 标签名
。标签的语法:标签名称前后需要紧跟两个冒号,例如::标签名::
。使用goto的一些限制条件- 不能直接跳转到一个代码块中的标签,因为代码块中的标签对外不可见
- goto不能跳转到函数外
- goto不能跳转到局部变量的作用域
--使用goto实现continue关键字的作用 -- 打印列表中的偶数 local list = {1,2,3,4,5,6}; for i = 1, #list do if i %2 ~= 0 then goto continue; end print(list[i], " "); ::continue:: end
- break:使用break语句用于结束循环,该语句会中断包含他的内层循环。
数学库常用函数
1.随机数发生器
- random:用于生成伪随机数
- randomseed:设置伪随机数发生器的种子。如果不设置其他的种子,则每次程序运行都会生成相同的伪随机数序列。
2.取整函数
- floor:向下取整
- ceil:向上取整
- modf:向0取整
表
- 使用表构造器(表构造器分为记录式构造器和列表式构造器)创建表
--使用构造表达式(最简单的表构造器)创建表,最简单的形式是{}
table = {}
--列表式构造器创建表
table = {100,200,"hello"}
--记录式表的语法创建表
table = {x = 100 ,y = 200}
print(table.x) --100
print(table.y) --200
--对于一个表而言,当程序中不再有指向它的引用时,垃圾收集器会最终删除这个表并重用其占用的内存
table = nil
- 表索引:同一个表中存储的值可以具有不同的 索引(即不同数据类型的键,nil除外),并可以按需增长以容纳新的元素。Lua语言中索引从1开始
a = {}
a.x = 100
print(a["x"])--100
print(a[x]) --nil
- 数组或者列表:使用整形作为表的索引即可
- 遍历表
--1.使用pairs迭代器遍历。
table = {100,"hello",print,false}
--1 100
--2 hello
--3 function: 0x41e230
--4 false
for key,value in pairs(table) do
print(key,value)
end
--2.对于列表则可以使用ipairs迭代器
for key,value in ipairs(table) do
print(key,value)
end
--3.使用数值型for循环
for i = 1,#table do
print(i,table[i])
end
- 表标准库:参看官方文档
- 判断空表问题
--1.判断空表的问题
function table_is_empty(t)
return _G.next( t ) == nil
end
print(table_is_empty({})) -- true表示这是一个空表
- 表格类型中深浅拷贝的问题
-- 表格类型中简单的浅拷贝
local table1 = {"hi"}
local table2 = table1
print("table1的地址为:",table1)
print("table2的地址为:",table2)
table2[1] = "world"
for key,value in pairs(table1) do
print(key..":"..value) -- 1:world
end
for key,value in pairs(table2) do
print(key..":"..value) -- 1:world
end
--表格类型中解决深拷贝的问题:递归拷贝
function clone(master)
if(not master or type(master) ~= "table") then -- 表不存在或者类型非表格
return nil
end
local temp = {}
-- 空表则直接返回空表
if(_G.next( master ) == nil) then
return temp
end
for k, v in pairs(master) do
if type(v) == "table" then
temp[k] = clone(v) --嵌套表格需要递归拷贝
else
temp[k] = v --非表类型可以直接拷贝,不存在深浅拷贝的问题
end
end
return temp
end
local table1 = {"hi"}
local table2 = clone(table1)
print("table1的地址为:",table1) -- 两者地址不一样
print("table2的地址为:",table2)
table2[1] = "world"
print(table1[1]) -- hi
print(table2[1]) -- world
- 表格中嵌套表格
--表格嵌套表格
local table1 = {{1,false},{2,false}}
for key,value in pairs(table1) do
print(value[1]) --1 2
end
local table = {[1] = {"hi","hello"},[2] = {"world","me"}}
for key,value in pairs(table) do
print(key,value[1]) -- 1hi 2world
end
- 安全访问:
nestedList = {
a = {
b = {
c = {name = 'NrvCer'}
}
}
};
emptyTable = {};
-- 安全访问示例
name = ((((nestedList or emptyTable).a or emptyTable).b or emptyTable).c or emptyTable).name;
print(name)
函数
- 实参个数可与形参个数不一致
--调用函数时使用的参数个数可以与定义函数时使用的参数个数不一致
function printValue(a,b)
print(a,b)
end
printValue() --nil nil
printValue(1)--1 nil
printValue(1,3,5)--1 3
- 函数可以返回多个值
--返回一个数组中的最大元素和索引
function getMax(a)
local index = 1
local maxVal = a[1]
for i = 2,#a do
if(a[i] > maxVal) then
index = i
maxVal = a[i]
end
end
return maxVal,index
end
maxVal,index = getMax({100,2,56,78,250,1})
print(maxVal,":",index) --250:5
- 具有可变长参数的函数
-- ...表示函数的参数是可变长的,如果需要遍历可变长参数,则使用表达式{...}
function add(...)
local sum = 0
for _,value in pairs({...}) do
sum = sum + value
end
return sum
end
print(add(1,2,3,4,5,6,7)) --28
- 尾调用:尾调用时不需要额外的栈空间,这也称作尾调用消除。在尾调用之后,程序就不需要在调用栈中保存有关调用函数的任何信息。尾调用函数返回时,程序的执行路径会直接返回到调用外层函数的位置,调用尾调用的函数栈就可以释放。
-- 尾调用时不使用额外的栈空间,所以该函数永远不会发生栈溢出
function printVal(n)
if n == 1 then
return 1
end
return n * printVal(n - 1)
end
print(printVal(10)) --3628800
- table中的常用函数:
- table.pack:返回一个表,表中保存所有参数,以及表示参数个数的字段n。组包
function func(...) local arg = table.pack(...); for i = 1, arg.n do print(i,arg[i]); end end func(1, nil, 3, 6, nil, 9); -- 1 1 -- 2 nil -- 3 3 -- 4 6 -- 5 nil -- 6 9
- table.unpack:将一个表转换成一组返回值。拆包
输入和输出
1.简单IO模型
- io.read:从标准输入流中读数据
- io.input
- io.output
- io.write
- io.read:函数参数可如下
- "a":读取整个文件
- "l":读取下一行,不保留换行符
- "L":读取下一行,保留换行符
- "n":读取一个数值
- num:读取num个字符
2.完整IO模型
- io.open
- IO库提供了三个预定义的c语言流的句柄:io.stdin、io.stdout、io.stderr
io.stderr:write("hhhhhh");