简介
Lua是一种轻量级的脚本语言,旨在嵌入应用程序中作为扩展语言使用。它由巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)的一组研究人员于1993年开发而成。
Lua的设计目标是提供一种简洁、高效、可嵌入和可扩展的脚本语言。它采用了简单的语法和动态类型系统,具有自动内存管理机制,以及一组基本的数据类型(包括nil、布尔、数字、字符串、表等)。Lua还支持面向对象编程、函数式编程和协同程序(coroutines),为开发者提供了很大的灵活性。
Lua可以被嵌入到其他主机语言(如C、C++、Java等)中,并通过提供简单的API接口进行交互。这使得开发者可以在自己的应用中使用Lua作为扩展语言,实现更高级的脚本功能,而不是使用繁琐的主机语言编写大量的代码。
Lua在游戏开发、嵌入式系统、网络编程、脚本扩展等方面得到了广泛应用。它的性能出色,具有较小的内存占用和快速的执行速度,因此在需要高效率和资源受限的环境中很受欢迎。
总的来说,Lua是一种简洁、轻量级、高效的脚本语言,非常适合用于嵌入式环境中,为应用程序提供灵活、可扩展的脚本功能。
正文
语言基础
一、语法规范
1.Lua区分大小写,例如: and 和And不一样
2.Lua标识符和名称有字母、数字和下划线组成(不能用数字开头),下划线+大写字母通常被Lua用作特殊用途,避免将其用作其他用途
3.注释
单行注释:
-- print("hello,lua")
多行注释:
--[[
print("hello.lua")
--]]
小技巧——快速取消多行注释:
在多行注释的开头添加一个 - 可以让多行注释失效,从而取消多行注释
---[[
print("hello.lua")
--]]
二、类型和值
lua语言有8种基本类型
nil 空
boolean 布尔
number 数值
string 字符串
userdata 用户数据
function 函数
thread 线程
table 表
print(type(nil))
print(type(true))
print(type(1.1*3))
print(type("hello lua"))
print(type(io.stdin))
print(type(print))
print(type(type))
print(type({
}))
print(type(type(X)))
--输出如下
nil
boolean
number
string
userdata
function
function
table
string
注:如果一个变量赋值给他nil,那么表示被销毁
三、数值运算
加减乘除,取余,大于小于,略。
lua5.3新增方法:
相当于普通除法后向下取整
3//2 --输出1
3//2.0 --输出1.0
数学库
例如三角函数,取整,绝对值,平方等,略。
-- 例如:
math.sin(20)
--其中math.modf是取整函数,是向0取整,意思是不管这个数是正还是负,向0的方向取整
math.modf(-1.5) --输出-1
math.modf(1.5) --输出1
随机数
随机数也是数学库的函数,但是需要单独写,有注意事项
基本用法:
使用随机数前需要添加上随机数种子,否则输出的随机数是固定的。
-- 这里我写了两遍输出随机数,这可不是随便写的,是故意的,因为第一次的随机数是固定的,第二次才是随机的。有没有被坑到?
math.randomseed(os.time())
print(math.random(5))
print(math.random(5)) --意思是在1-5 这5个数之间随机取一个
--如果是 math.random(7,9)那么就是在7-9 这3个数之间随机取一个
lua数值表示范围
这个也是属于数学库函数
math.maxinteger
四、字符串
字符串库
string.sub 截取一段
--例如
string.sub("hello",1,1) --输出 h
--解释 string.sub(s,i,j) ,从字符串s中提取第i个到第j个字符,包含ij
--其中 ij可以为负数,表示倒数,例如-1表示倒数第一个字符,-2表示倒数第二个字符
string.sub("hello",2,-2) --输出 ell
string.format 格式化字符串
----常用格式化----
%d 表示整数
%02d 表示 输出两位数,前面用0填充
%x 表示输出为16进制格式的整数
%f 表示输出为浮点数
%.4f 表示输出为小数部分有四位
%s 表示输出为字符串
d=5;m=8;y=1998
string.format("%02d/%02d/%04d",d,m,y) --输出05/08/1998
string.format("pi=%.4f",math.pi) --输出pi=3.1416
str="hello"
print(string.format("world %s",str)) --输出 world hello
print(string.format("x=%d y=%d",10,20)) --输出 x=10 y=20
string.find 查找某个字符串在第几个位置,从1开始
string.find("hello world","wor") --输出 7 9 表示第7到第9个字符串
string.find("hello world","war") --输出 nil
string.gsub (Global SUBstitution)找到某个字符并替换为指定字符
-- 查找 l 字符, 用 . 替代,输出替换后的字符串,并且输出替换的个数
string.gsub("hello world","l",".") --输出 he..o wor.d 3
-- 查找 ll 字符,用 . 替代
string.gsub("hello world","ll","..") --输出 he..o world 1
string.gsub("hello world","ll",".") --输出 he.o world 1
string.rep 重复某个字符串
string.rep("a",2^20) --返回一个 1MB 大小的全是a的字符串
string.rep("a",3) --返回字符串 "aaa"
string.len 返回该字符串的长度
str=string.rep("a",3)
print(string.len(str)) --输出 3 ,这个方法与 #"aaa" 方法等价
string.reverse 字符串翻转
string.reverse("abc") --输出 "cba"
string.lower 将字符串转换成字母小写
string.upper 将字符串转换成字母大写
string.byte 与 string.char 互转字节和字符
print(string.char(97)) --输出 a
print(string.byte("a")) --输出 97
-----拓展------
i=97
print(string.char(i,i+1,i+2)) --输出 abc
print(string.byte("abc",2)) --输出 98
print(string.byte("abc",-1)) --输出 99
print(string.byte("abc",1,2)) --输出 97 98 这里表示的是字符串第一个到第二个字符的字节是什么
print(string.byte("abc",1,-1)) --输出整个字符串对应的字节
utf8库
lua5.3支持
1.字符串常量
单引号和双引号等价
a="hello"
a='hello'
输出字符串长度
print(#"hello") --输出 5
--------------------------------
a="hello"
print(#a) --输出 5
lua支持的转义字符
\a --响铃
\b --退格
\f --换页
\n --换行
\r --回车
\t --水平制表符
\v --垂直制表符
\\ --反斜杠
\" --双引号
\' --单引号
2.多行字符串
str = [[
123
hello
nihao
]]
print(str)
--输出
123
hello
nihao
3.字符串与数字的强制类型转换
- 数字转字符串
print(tostring(10)=="10") --输出true
使用 .. 连接符号,注意这里的符号前后都有一个空格
print(10 .. 20) --输出 1020
- 字符串转数字
字符串转数字,不同进制的数字
print(tonumber(" -5 ")) --输出 -5
print(tonumber(" 10e4 ")) --输出 100000
--指定进制的转换
print(tonumber("100110",2)) --输出 38
print(tonumber("987",8)) --输出 nil,因为9超过了8进制,所以返回空 nil
print(tonumber("fff",16)) --输出 4095
print(tonumber("-ZZ",36)) --输出 4294966001
直接使用加号,可以将字符串相加后变为数值
print("10"+1) --输出 11
五、表
类似于数组,map,类的数据结构
-------初体验
a={
}
m="n"
a[m]=10 --这里 "n"是键,10是值
print(a["n"]) --输出 10
a[3]="hello" --这里 3 是键,"hello"是值
a["n"] --这里 "n"是键,10是值
m=3
print(a[m]) --这里 3是键,"hello"是值
a["n"] = a["n"]+1 --这里a["n"]=11
a[3]=20
print(a[3]) --输出20
表标准库
table.insert 插入
t={
}
table.insert(t,"one")
table.insert(t,"two")
table.insert(t,3,10)
for k, value in ipairs(t) do
print(k,value)
end
--输出
1 one
2 two
3 10
table.remove 删除某元素
t={
}
table.insert(t,"one")
table.insert(t,"two")
table.insert(t,3,10)
table.remove(t,2)
for k, value in ipairs(t) do
print(k,value)
end
--输出
1 one
2 10
table.move 移动元素
---table.move(a,e,f,t)
---表示将表a 的 e到f 上的元素移动到 t的位置上
t={
}
table.insert(t,"one")
table.insert(t,"two")
table.move(t,1,#t,2)
t[1]="move"
for k, value in ipairs(t) do
print(k,value)
end
--输出
1 move
2 one
3 two
1. 表构造器
可以分为记录式和列表式
table = {
color="red", --记录式
point=5,
{
x=0,y=0}, --列表式
{
x=1,y=1},
{
x=2,y=2}
}
print(table[1].x) --输出0
print(table.point) --输出5
2.遍历表
通常,遍历表都是随机的,但是元素只会遍历输出一次,
----------------使用pairs是随机输出-------------------
table = {
color="red", --记录式
point=5,
{
x=0,y=0}, --列表式
{
x=1,y=1},
{
x=2,y=2}
}
for k, v in pairs(table) do
print(k,v)
end
--输出
1 table: 000000000102a860
2 table: 000000000102a7e0
3 table: 000000000102aca0
point 5
color red
------------使用 ipairs 是顺序输出------------------
table={
10,print,12,"hi"}
for k, v in ipairs(table) do
print(k,v)
end
--输出
1 10
2 function: 00000000684989c0
3 12
4 hi
还有用关键字遍历的方式
table={
10,print,12,"hi"}
for i = 1, #table do
print(i,table[i])
end
--输出
1 10
2 function: 00000000684989c0
3 12
4 hi
六、函数
格式
function add(a)
local sum =0
for i = 1, #a do
sum = sum +a[i]
end
return sum
end
t = {
1,2,3,4,5}
print(add(t))
1.多返回值
function add(a)
return a[1],a[2]
end
t = {
1,2,3,4,5}
print(add(t))
--输出
1 2
2. 可变长参数函数
function add(...)
local s=0
for _, value in ipairs(...) do
s=s+value
end
return s
end
t = {
1,2,3,4,5}
print(add(t))
--输出
15
3.函数 table.pack
将一些零散的值返回成一个表
print(type(table.pack(1,2,3,4)))
--输出
table
4.函数 table.unpack
将一个表拆散成多个变量
print(table.unpack({
1,2,3,4,5}))
--输出 1 2 3 4 5
a,b=table.unpack({
1,2,3,4,5})
print(a,b)
--输出 1 2
print(table.unpack({
1,2,3,4,5},2,3))
--输出 2 3
f = string.find
print(f(table.unpack({
"hello","ll"})))
--输出 3 4
5.尾递归调用
function f(x)
x=x+1
return g(x)
end
七、控制结构
if ...else then ...end
sum = 0
a=10
if a<0 then
sum=1
elseif a<2 then
sum=2
elseif a<4 then
sum=4
else
sum=5
end
print(sum)
--输出 5
while do
a=1
sum=0
while a<10 do
sum = sum+1
a=a+1
end
print(sum)
--输出 9
repeat...until
sum =10
repeat
sum = sum-1
print(sum)
until sum<0
for 循环
sum =10
t = {
1,2,3,4}
for k, value in ipairs(t) do
print(k,value)
end
--输出
1 1
2 2
3 3
4 4
for i = 1, 10, 2 do
print(i)
end
--输出
1
3
5
7
9
八、输入输出
io.write
io.write和print 的区别有
print会自动换行
io.write可以重定向,print不能
- io.write可以精准控制输出流,例如输出个数
io.write("test")
io.write("test")
print("hello")
print("hello")
--输出
testtesthello
hello
file = io.open("data.txt","a")
io.output(file)
io.write("www.com")
io.close(file)
io.read
等同于 io.input():read(args)
从当前输入流中读取字符串
这个需要参数
"a" 读取整个文件
"l" 读取下一行(丢弃换行符)
"L" 读取下一行(保留换行符)
"n" 读取一个数值
num 以字符串读取num个字符
io.lines
io.input("data.txt")
for line in io.lines() do
print(line)
end
--输出
hel
ddd
---上面的可以写成
for line in io.lines("data.txt") do
print(line)
end
-------------------
--如果给io.lines 一个参数,那么这个数字表示一行的大小,可以减少访问次数
--加入data.txt有两行数据
-------------下面执行一次---------------
num=0
for line in io.lines("data.txt",2^8) do
print(line)
num = num+1
end
print(num)
--num输出 1
------------下面执行两次-------------
num=0
for line in io.lines("data.txt") do
print(line)
num = num+1
end
print(num)
--num输出 2
简单IO模型
简单IO模型包含io.input,io.output, io.read, io.write
io.input输入流
--1.输入流
--注意这个文件默认处于当前工作空间下才能读取到
--当前工作空间参考vscode工作区概念
--另外,需要print或者io.write输出读取到的内容
--1.1默认输入流
--默认的io.input输入流是控制台,所以执行后可以在控制台输入字符,然后回车后会读取
io.input()
print(io.read())
--输入 aaa
--输出 aaa
--2指定输入流为某文件
io.input("data.txt")
print(io.read()) --读取一行
--2.1维持默认输入流
--如果此时在后面的io.input不添加参数,那么默认输入流默认是“data.txt”文件
--例如:
io.input("data.txt")
print(io.read()) --读取一行
io.input()
print(io.read()) --读取一行
--2.2修改输入流
--如果添加参数,那么会改变默认输入流
io.input("data.txt")
print(io.read()) --读取一行
io.input("ni.txt")
print(io.read()) --读取一行
io.output输出流
--1.输出流
--默认输出流是控制台输出,默认输出到控制台
io.output()
io.write("niho")
--输出 niho
--2.指定文件输出流
io.output("hello.txt")
io.write("niho")
--这段文字输出到这个文件,文件不存在会自动创建
综合案例:利用简单IO模型,读取整个文件的内容并输出
--方式一
io.input("data.txt")
for i = 1, math.huge do
local line = io.read("L")
if line==nil then
break
end
io.write(line)
end
--方式二 利用IO.lines
io.input("data.txt")
for line in io.lines() do
io.write(line,"\n")
end
--方式三 将所有行读取到表里面
io.input("data.txt")
t={
}
for line in io.lines() do
t[#t+1] = line --读到表里
end
for k, value in pairs(t) do
print(k,value) --输出表
end
完整IO模型
与简单IO模型相比,完整IO模型更适用于多个文件
完整IO模型是基于file句柄然后加上 : 引号来调用特别的方法,让IO更加强大
--读取文件
file = io.open("data.txt","r")
print(file:read("a"))
file:close()
完整IO模型中的方法大多参考的C语言中的IO方法
file = io.open("data.txt","r")
file:seek("set",1) --设置文件句柄从哪个字符开始读,第一个字符是0,第二个是1,这里从第二个字符开始
print(file:read("a"))
--输出
输出结果将从第二个字符开始
还有其他很多方法,可以参考c语言对应方法的用法
文件I/O
io.open/io.close
读取文件,第一个参数是文件名,第二个是打开的权限
file = io.open("test.txt","r")
io.input(file)
print(io.read())//读取一行
io.close(file)
九、常见系统命令
os.rename
给文件改名
--第一个参数是旧名字,第二个参数是新名字
os.rename("data.txt","da.txt")
os.remove
删除文件
os.remove("ww.lua")
os.getenv
获取环境变量
--参数是环境变量的变量名
print(os.getenv("MAVEN_HOME"))
--输出
输出Maven的环境变量
os.execute("java -version")
在当前系统执行一条信息
io.popen
和上面的作用一样,在当前系统执行一条命令,但是可以设置为 r模式,将流信息重定向输入到文件中
file = io.popen("java -version","r")