Lua语言快速入门 · 教程笔记
- 前言
- 1. Lua 语言介绍
- 2. Lua 语言基础之基本语法
- 声明变量
- 声明方法
- 使用 if - else
- 使用 for
- 使用 while
- 3. Lua 语言基础之表
- 4. Lua 语言基础之数组
- 插入元素
- 移除元素
- 获取表的长度
- 全局表
- 5. Lua 语言面向对象之复制表的方式面向对象
- 实现继承和重写父类方法
- 6. Lua语言面向对象之函数闭包的方式面向对象
- 实现继承和重写父类方法
- 额外补充
- 字符串补充
前言
笔记的内容出自 Bilibili 上的这两个视频:
Lua语言快速入门精通(第 1 ~ 6 集)
【无废话30分钟】Lua快速入门教程 - 4K超清
前者组成了笔记的主要结构,后者作为前者的补充。笔记主要用于供笔者个人或读者回顾知识点,如有纰漏,烦请指出 : )
1. Lua 语言介绍
一般是使用 C/C++ 来实现功能,用 Lua 来实现逻辑。因为 Lua 作为一种动态的脚本语言,它可以在调用时进行解释或编译,不用像静态语言那样编译完毕才能运行。
2. Lua 语言基础之基本语法
声明变量
在 Lua 里,直接声明一个变量的话,它是作为全局变量存在的,它在另一个文件里也可以用。
如果想让它只对本地有作用则需要在前面加个 local。
num1 = 100 -- 作用于全局
local num2 = 200 -- 作用于本地
- 在 Lua 里,
nil
代表空值。 - 在其他语言里 “不等于” 是
!=
,但在 Lua 里是~=
(波浪号和等于号) - 在 Lua 里,
nil
和false
才代表 false;其他所有数都代表 true,包括0
。
声明方法
最基础的方法声明与调用,如下所示:
-- 声明方法
function sayHello()
print("Hello Lua")
end
sayHello() -- 调用,输出 Hello Lua
使用 if - else
声明带参数的方法与调用,如下所示:
function max(a, b)
-- if 语句的运用
if a > b then
return a
else
return b
end
end
print(max(2, 3)) -- 输出 3
- 如果中间想继续判断就用
elseif {表达式} then
。
使用 for
使用 for 循环:
-- 输出 1 到 100
for var = 1, 100 do
print(var)
end
- break 可以用于终止 for 和 while 的循环。
使用 while
使用 for 循环:
-- 输出 1 到 100
local var = 1
while var < 101 do
print(var)
var = var + 1 -- 注意,Lua 不支持自减(-=)和自增(+=)
end
3. Lua 语言基础之表
表相当于一个装载键值对的容器,但是它里面什么都可以存放,示例如下:
Config = {} -- 声明一个空表
-- 声明两个键值对
Config.words = "Hello" -- 键是 words,值是 "Hello"
Config.num = 100 -- 键是 num,值是 100
-- 用中括号 [] 来声明键值对
Config["name"] = "ZhangSan" -- 此处可看出键实际上是字符串
-- 通过表和键输出值
print(Config.words) -- 输出 Hello
print(Config["num"]) -- 输出 100,如果不添加双引号则为 nil(为空)
由上我们可以得出一个规律:
- 用
.
和键获取表内元素的时候 不需要" "
; - 用
[ ]
和键获取表内元素的时候 配套使用" "
我们也可以在声明表的同时声明内部元素,并且用 for 来遍历内部元素
-- 在声明表的同时声明内部元素
Config1 = {hello = "Hello lua", world = "World"}
-- 用 for 遍历表内元素
for key, var in pairs(Config1) do
print(key, var)
end
-- 输出如下(乱序输出)
--hello Hello lua
--world World
4. Lua 语言基础之数组
数组跟表一样也是用 { }
来代表,不过声明内部元素的时候不需要提供键,它会自动从 1 开始递增式为元素配置键。
arr = {1, 2, "Hello"}
-- 用 for 遍历数组内键值对
for key, var in pairs(arr) do
print(key, var)
end
-- 输出如下
--1 1
--2 2
--3 Hello
插入元素
我们可以通过 for 为表添加元素,这时候要用到 Lua 提供的一个 API:table.insert()
arr1 = {}
for var = 1, 3 do
table.insert(arr1, 1, var) -- 3个形参按顺序分别是:表,插入位置,值
end
for key, var in pairs(arr1) do
print(key, var)
end
-- 输出如下
--1 3
--2 2
--3 1
我们可以从上面的输出结果看出来,固定往位置 1 分别插入 1、2、3,原来处于位置 1 的值就会被往后推,最后就呈一个倒序的样子。
Lua 官网的 Document 里可以找到其 API 文档(此处为 5.4 版本),方便我们查阅 Lua 提供的方法的作用。其 API 基本就是对 C 语言 API 的一个映射。
下图截取自官方的 API 解析:
移除元素
我们可以通过 table.remove()
来移除表内的元素,并且这个方法会返回被移除的元素的值。
arr2 = {1, 2, 3, 4}
local rm = table.remove(arr2, 2) -- 移除第 2 个元素
for key, var in pairs(arr2) do
print(key, var)
end
print(rm)
-- 输出如下
--1 1
--2 3
--3 4
--2
获取表的长度
在 lua 5.2 及之前的版本,我们还可以通过 table.maxn()
来获取表的长度。如果是 lua 5.3 及以上的版本,我们可以用 #
来获取表的长度。
print(table.maxn(arr1)) -- 输出 3(仅适用于 lua 5.2 及以下版本)
print(#arr1) -- 输出 3(仅适用于 lua 5.3 及以上版本)
全局表
在 Lua 里,所有的全局变量都被放在一个名为 _G
的全局表里。
a = 1
print(_G["a"]) -- 输出 1
并且实际上 table.insert()
里的 table
也是一个全局变量,其类型是一个表;insert
就是它的一个键,其值是一个方法。
5. Lua 语言面向对象之复制表的方式面向对象
在表里面声明方法的写法如下:
People = {}
-- 声明方法的方式一
People.sayHi = function()
print("People say hi")
end
-- 声明方法的方式二
function People.sayHello()
print("People say hello")
end
此时我们可以发现表也可以当作是一个类,因为它既可以存储变量,又可以存储方法,所以表在 Lua 里是一个比较万金油的角色。
通过复制 People 类来创建它的实例:
-- 复制表内元素,返回这个复制表
function clone(tab)
local ins = {}
for key, var in pairs(tab) do
ins[key] = var
end
return ins
end
-- 相当于创建实例
local p = clone(People)
p.sayHi() -- 输出 People say Hi
我们还可以为类添加一个构造方法:
-- 修改一下 sayHi()
People.sayHi = function(self)
print("People say hi:"..self.name) -- ".." 是字符串连接符号
end
-- People 的构造方法
People.new = function(name)
local self = clone(People)
self.name = name
return self
end
local p = People.new("ZhangSan")
p.sayHi(p) -- 输出 People say hi:ZhangSan
-- 另一种调用方式
p:sayHi() -- 使用 ":" 调用,输出同上
通过 :
调用方法,其实就是隐式地把表自己当作第一个实参传递,即 tab:func(param)
相当于 tab.func(tab, param)
。
那么反过来,通过 :
来定义方法,实际上隐藏了一个形参的声明,这个形参会截获调用函数时的第一个实参并把它赋值给self。
此处结论截取自其他博主的文章:《Lua函数的调用(:和.的调用区别)》
实现继承和重写父类方法
我们还可以通过复制表的内容来实现类的继承,并且可以重写父类方法。
-- 复制表的内容
function copy(dist, tab)
for key, var in pairs(tab) do
dist[key] = var
end
end
-- Man 继承 People
Man = {}
Man.new = function(name)
local self = People.new(name)
copy(self, Man) -- 将 Man 原本的内容也复制到 self 内
return self
end
-- 重写父类 People 的 sayHello() 方法
Man.sayHello = function()
print("Man say hello")
end
local m = Man.new("Lisi")
m:sayHello() -- 输出 Man say hello
m:sayHi() -- 输出 People say hi:Lisi
6. Lua语言面向对象之函数闭包的方式面向对象
我们可以专门声明一个返回表的方法,其中通过本地声明一个表,然后对其进行初始化操作以及方法定义的操作,这样我们就可以通过这个方法来获得一个类的实例。
function People(name)
local self = {}
local function init()
self.name = name
end
self.sayHi = function()
print("Hi "..self.name)
end
init()
return self
end
local p = People("ZhangSan")
p:sayHi() -- 输出 Hi ZhangSan
实现继承和重写父类方法
操作比较好理解,示例如下:
function Man(name)
local self = People(name)
self.sayHello = function()
print("Hello "..self.name)
end
return self
end
local m = Man("Lisi")
m:sayHi() -- 输出 Hi Lisi
额外补充
字符串补充
Lua 提供的 string.char()
可以将 Ascii 码值转换成字符串;string.byte()
可以直接将字符串里的指定位字符转换为十进制数值。
s = string.char(0x30, 0x31, 0x32, 0x33)
print(s) -- 输出 0123
n = string.byte(s, 2)
print(n) -- 输出 49(Ascii 表里,十进制 49 对应的是字符 '1')
在 C 语言里,字符串的 ‘0’ 代表着结束;但是在 Lua 里字符 ‘0’ 也可以被存储。这个特性可以用于安全地存储二进制流之类的数据。