1 Lua 简介
Lua 是一个小巧的脚本语言,用标准C语言编写而成,由巴西里约热内卢天主教大学的 Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo 三人于 1993 年开发,设计目的是为了灵活嵌入应用程序,实现灵活的扩展和定制功能。
Lua 具有以下特性:
- 脚本语言、解释型语言
- 嵌入程序开发
- 容易与其他语言相互调用
- 轻量级
- 面向过程编程
- 函数式编程
- 热更新
2 Lua 环境搭建
1)下载 bin 包
点击 https://luabinaries.sourceforge.net/download.html,根据系统类型下载相应 bin 文件,如:Windows 系统下载 lua-5.4.2_Win64_bin.zip,如下:
2)解压并重命名文件
将下载的 bin 文件解压,如笔者解压路径:D:\Program Files\Lua\bin,并将 lua54.exe 文件重命名为:lua.exe,如下:
3)配置环境变量
右键此电脑,依次选择【属性→高级系统设置→环境变量→系统变量→Path】,将解压的 bin 目录添加到系统环境变量 Path 中。
4)验证环境
在 cmd 命令行窗口输入:lua -v,如果打印了版本号,说明环境配置成功,如下:
3 Lua 输出、输入和注释
3.1 输出
1)在命令行中输入 Lua 代码
在命令行中输入 lua,回车后进入 Lua 解释器环境,再输入 print("Hello World"),运行如下:
按 Ctrl + C 即可退出 Lua 解释器环境。
2) 调用文件中 Lua 代码
用记事本创建一个文件,重命名为 test.lua,编辑内容如下:
print("Hello World")
使用命令行进入 test.lua 文件所在目录,输入:lua test.lua,打印如下:
3.2 输入
inputStr = io.read() --运行后会等待用户输入, 按回车键结束输入
3.3 注释
1)单行注释
--单行注释
2)多行注释
--[[
多行注释
]]
4 运算符
4.1 算术运算符
加(+)、减(-)、乘(*)、除(/)、幂(^)、取余(%)
4.2 比较运算符
小于(<)、大于(>)、小于等于(<=)、大于等于(>=)、等于(==)、不等于(~=)
4.3 逻辑运算符
与(and)、或(or)、非(not)
a and b --如果a为false, 则返回a, 否则返回b
a or b --如果a为true, 则返回a, 否则返回b
not a --如果a为true, 则返回 false, 否则返回false
补充:Lua 中只有 false 和 nil 为假, 其他任何值都为真, 0 也为真。
案例:
print(1 and 2) --2
print(0 and nil) --nil
print(0 or 1) --0
print(not 0) --false
print(not nil) --true
5 Lua 变量
变量的名称必须由字母、数字或下划线字符组成,且必须以字母或下划线开头。 大写和小写字母是不同的,因为 Lua 区分大小写。
5.1 数据类型
nil --空值,所有没有使用过的变量都是 nil,nil 既是值,又是数据类型
boolean --布尔型, 只有2个值, true和false
number --数值类型, 相当于C语言里的double
string --字符串
table --关系类型
function --函数类型
获取数据类型:
--nil number string boolean
print(type(nil), type(1), type("xxx"), type(true))
5.2 变量声明与赋值
1)全局变量与局部变量
--声明全局变量
a = 5
b = true
--声明局部变量
local name = "zhang san"
print(a, b, c, name) --5 true nil zhang san
说明:nil 是 Lua 中的空值,所有没有使用过的变量都是 nil,nil 既是值,又是数据类型。
2)一组变量赋值
a, b, c = 1, true, "zhang san"
print(a, b, c) --1 true zhang san
d, e = 2
print(d, e) --2 nil
f, g = 3, 4, 5
print(f, g) --3 4
3)交换变量的值
a, b = 1, 2
a, b = b, a
print(a, b) --2 1
6 字符串
6.1 字符串定义
a = "xxx"
b = 'yyy'
c = [["zzz"]]
d = [['www']]
print(a, b, c, d) --xxx yyy "zzz" 'www'
6.2 字符串链接
print("xxx".."yyy") --xxxyyy
print("xxx"..123) --xxx123
6.3 字符串与其他类型转换
tonumber("123") --字符串转换为数字
tostring(123) --其他类型数据转换为字符串
6.4 字符串函数
string.len(arg) --计算字符串长度
string.upper(str) --字符串全部转为大写字母
string.lower(str) --字符串全部转为小写字母
string.reverse(arg) --字符串反转
string.char(arg) --将整型数字转成字符并连接
string.byte(arg[,int]) --转换字符为整数值(可以指定某个字符,默认第一个字符)
--截取字符串, str: 待截取的字符串, i: 截取开始位置, j: 截取结束位置, 默认为-1, 表示最后一个位置
string.sub(str, i [, j])
--字符串替换, mainStr: 要操作的字符串, findStr: 要匹配的字符串, replaceStr: 替换的字符串, num: 替换次数(可以忽略,忽略后表示全部替换), return: 替换后的字符串和替换次数
string.gsub(mainStr, findStr, replaceStr, num)
--在str中查找subStr的, 如果找到了返回匹配的起点和终点索引, 否则返回nil
string.find (str, subStr, [init, [end]])
string.rep(string, n) --返回字符串string的n个拷贝
--字符串格式转换
string.format(...)
7 表格 table
7.1 字典
1)字典初始化
tab = {
name = "zhang san",
age = 23,
single = true
}
--zhang san 23 true nil nil
print(tab["name"], tab["age"], tab.single, tab.xxx, tab[yyy])
2)字典赋值
tab = {}
tab[0] = 1
tab["name"] = "zhang san"
tab.single = true
--1 zhang san true
print(tab[0], tab["name"], tab.single)
7.2 列表
1)列表初始化
tab = {1, 2, 3}
--nil 1 2 3
print(tab[0], tab[1], tab[2], tab[3])
说明:如果不设置下标,元素从 1 开始计数。
2)列表初始化(通过索引指定元素位置)
tab = {
1, 2, 3,
[0] = "Hello",
[10] = true
}
--Hello 1 2 3 true
print(tab[0], tab[1], tab[2], tab[3], tab[10])
8 流程控制语句
8.1 if 条件语句
1)if 语句
if conditions then
then-part
end
2)if - else 语句
if conditions then
then-part
else
else-part
end
3)if -elseif -else 语句
if conditions then
then-part
elseif conditions then
then-part
else
else-part
end
8.2 循环语句
1)for 循环语句
--start: 起点(包含), end: 终点(包含), step: 步长或增量(可省略)
for var = start, end, step
loop-part
end
2)泛型 for 循环语句
--只打印列表元素
for i, v in ipairs(table) do
loop-part
end
--打印所有元素
for k, v in pairs(table) do
loop-part
end
案例 1:
tab = {10, true, "xxx"}
for i, v in ipairs(tab) do
print(i, v)
end
--[[打印如下:
1 10
2 true
3 xxx
]]
案例 2:
tab = {10, true, "xxx"}
tab[0] = "yyy"
tab["zzz"] = 100
for i, v in ipairs(tab) do
print(i, v)
end
--[[打印如下:
1 10
2 true
3 xxx
]]
案例 3:
tab = {10, true, "xxx"}
tab[0] = "yyy"
tab["zzz"] = 100
for k, v in pairs(tab) do
print(k, v)
end
--[[打印如下:
1 10
2 true
3 xxx
0 yyy
zzz 100
]]
3)while 循环语句
while condition do
loop-part
end
4)repeat 循环语句
--类似C语言的do-while语句
repeat
loop-part
until condition
5)break
在循环过程中提前跳出循环,用法同C语言,如:
for i = 1, 10, 2
if i > 6 then
break
end
end
9 函数
9.1 函数定义与使用
1)函数定义
function function_name(args)
function-body
end
说明:Lua 函数不支持重载,对于不同参数的同名函数,只有最后一个定义的同名函数生效。
2)函数使用
function show(str)
print(str)
end
--直接调用函数
show("xxx") --xxx
--可以省去括号
show "yyy" --yyy
--函数赋值后再调用, 类似C语言的函数指针
func = show
func("zzz") --zzz
注意:函数调用应该放在函数声明后面,否则会报错。
9.2 函数返回值
Lua 支持多返回值,并且接收变量个数不一定要和函数返回参数个数一致。
function get()
return 1, 2, 3
end
--接收变量个数=返回参数个数
a, b, c = get()
print(a, b, c) --1 2 3
--接收变量个数<返回参数个数
a, b = get()
print(a, b) --1 2
--接收变量个数>返回参数个数
a, b, c, d = get()
print(a, b, c, d) --1 2 3 nil
9.3 匿名函数
func = function()
print("anonymous function")
end
func()
9.4 常用 math 函数
--幂函数
sqrt、pow
--指数与对数函数
exp、log、log10
ldexp --如: math.ldexp(10, 3), 值为10*2^3=80
--三角函数
sin、cos、tan、acos、asin、atan
--取整函数
ceil、floor
--最值函数
min、max
--双曲线函数
cosh、sinh、tanh
--角度与弧度转换函数
deg、rad
--随机函数
random --如: math.random(1, 100), 获取1-100的随机数
randomseed --设置随机数种子, 如: math.randomseed(os.time())
--其他函数
abs
modf --把数分为整数和小数, 如: math.modf(10.12), 返回10 12
说明:使用 math 函数,都需要在前面加上 “math.”,如:math.abs(-1)。
10 模块
myMath.lua
function add(a, b)
return a + b
end
function mul(a, b)
return a * b
end
test.lua
require("myMath")
print(add(1, 2)) --3
print(mul(2, 3)) --6
11 元表 metatable
元表的作用主要是为了模拟面向对象特性,元表主要有 __index、__newindex、__call、__tostring 元方法。
11.1 设置元表
son = {}
parent = {}
newSon = setmetatable(son, parent)
print(newSon == son) --true
print(newSon == parent) --false
11.2 __index 元方法
1)__index 是个表格
在读取子表的属性或函数时,若子表里不存在,就去元表的 __index 表里搜索,若元表也没有,就递归搜索元表的元表。
son = {
name = "son name",
func = function()
print("son func")
end
}
parent = {
__index = {
name = "parent name",
age = 23,
func = function()
print("parent func")
end,
show = function()
print("show")
end
}
}
setmetatable(son, parent)
print(son.name) --son name
print(son.age) --23
son.func() --son func
son.show() --show
2)__index 是个方法
在读取子表的属性时,若子表里不存在,就调用元表的 __index 函数。
案例一:
son = {}
parent = {
__index = function()
print("parent __index")
end
}
setmetatable(son, parent)
print(son.age)
--[[打印:
parent __index
nil
]]
案例二:
son = {}
parent = {
__index = function(tab, key)
print(tab, key)
end
}
setmetatable(son, parent)
print(son.age)
--[[打印:
table: 0000000000179fd0 age
nil
]]
11.3 __newindex 元方法
1)__newindex 是个表格
在修改子表的属性时,若子表里不存在,就在元表的 __newindex 表里添加该属性。
tempTab = {}
son = {}
parent = {
__newindex = tempTab
}
setmetatable(son, parent)
son.name = "son name"
print(son.name) --nil
print(tempTab.name) --son name
2)__newindex 是个方法
在修改子表的属性时,若子表里不存在,就调用元表的 __newindex 函数。
案例一:
son = {}
parent = {
__newindex = function()
print("parent __newindex")
end
}
setmetatable(son, parent)
son.name = "son name"
print(son.name)
--[[打印:
parent __newindex
nil
]]
案例二:
son = {}
parent = {
__newindex = function(tab, key, value)
print(tab, key, value)
end
}
setmetatable(son, parent)
son.name = "zhangsan"
print(son.name)
--[[打印:
table: 0000000000099cd0 name zhangsan
nil
]]
11.4 __call 元方法
在以函数形式调用子表时(如:tab()),会调用元表的 __call 函数。
1)无参 call
son = {}
parent = {
__call = function()
print("parent __call")
end
}
setmetatable(son, parent)
son() --parent __call
2)有参 call
son = {}
parent = {
__call = function(sonTab, arg)
print(sonTab, arg)
end
}
setmetatable(son, parent)
son("xxx") --table: 0000000001019c90 xxx
说明:第一个参数是调用的子表。
11.5 __tostring 元方法
在获取子表输出内容时,会调用元表的 __tostring 函数。
son = {10, 20, name = "zhangsan"}
parent = {
__tostring = function(sonTab)
str = "{"
for k, v in pairs(sonTab) do
str = str..k..": "..v..", "
end
str = str.."}"
return str
end
}
setmetatable(son, parent)
print(son) --{1: 10, 2: 20, name: zhangsan, }
12 面向对象编程
Lua 是面向过程编程语言,不支持面向对象编程,但可以使用元表模拟面向对象编程。本节将通过一个案例展示 lua 面向对象编程的写法。
student.lua
--使用lua模拟一个类
--1、创建表格, 添加字段
Student = {
name = "xxx",
age = 0,
sex = "0"
}
--2、定义类的构造函数
function Student:new(name, age, sex)
o = {}
setmetatable(o, self)
self.__index = self;
self.__tostring = function()
return "{name: "..self.name..", age: "..self.age..", sex: "..self.sex.."}"
end
self.name = name
self.age = age
self.sex = sex
return o
end
--3、定义类的成员方法
function Student:show()
print(self.name, self.age, self.sex)
end
--4、定义静态字段
Student.hair = "black"
--5、定义静态方法
function Student.showHair()
print("hair=" .. Student.hair)
end
test.lua
require("student")
--创建Student实例
stu = Student:new("zhang san", 23, "male")
--调用Student的元表的tostring方法, 打印: {name: zhang san, age: 23, sex: male}
print(stu)
--访问stu实例的字段, 打印: zhang san 23 male
print(stu.name, stu.age, stu.sex)
--调用stu实例的方法, 打印: zhang san 23 male
stu:show()
--访问Student的静态字段, 打印: black
print(Student.hair)
--调用Student的静态方法, 打印: hair=black
Student.showHair()