Lua语言学习笔记
0. 环境准备
0.1 简介
Lua是由标准C编写而成的脚本语言,诞生于1993年,具有高效性、可移植性、可嵌入性、简单强大、小巧轻便、免费开源等诸多优点,主要应用场景包括做为嵌入脚本、做为独立脚本、用于应用程序的动态配置、游戏开发以及Web应用脚本等。
0.2 Windows下载与安装Lua
- 选择合适版本的Lua语言开发包下载
- 解压下载好的Lua压缩包到合适的路径
- 将Lua的解压路径添加到环境变量
Path
中 - 打开Windows命令行工具,输入指令
lua
,命令行输出Lua版本信息,安装成功
0.3 CentOS下载与安装Lua
curl -R -O http://www.lua.org/ftp/lua-5.4.4.tar.gz # 拉取合适的Lua包 |
0.4 推荐IDE
- VSCode(微软出品) + Lua扩展插件(Tencent出品)
- 在线IDE https://replit.com/languages/lua
1. 基本数据类型
1.1 table
table类型是一个"关联数组",需要注意:
- table的索引可以是数字或者是字符串,所有索引值都需要用
[
和]
括起来,如果是字符串,还可以去掉引号和中括号 - table的默认初始索引一般以1开始,如果不写索引,则索引会被认为是数字,并按顺序自动从1往后排
- table变量只是一个地址引用,对table操作不会产生数据影响
- table不固定长度大小,有新数据插入时长度会自动增长
- table里保存数据可以是任何类型,包括
function
和table
- table所有元素之间用逗号
,
隔开
-- 初始化 |
1.2 string
string类型可以使用双引号""
或单引号''
声明,如果是块字符串,可以以[[
开始,以]]
结尾。
字符串不可修改值,可以通过string.gsub
函数来替换字符串中的子串。
a = '1024' |
1.3 number
number类型只有一种,即双精度浮点double类型
a = 1024 |
1.4 boolean
boolean类型只有两个可选值:true(真)和 false(假)。判断时false和nil都是假,其他都为真。
a = true |
1.5 nil
nil类型表示一个无效值,只有值nil
,如果打印没有赋值的变量,则会输出nil。
print("first: ", a) |
注意:要判断变量是否为 nil 的时候,需要使用 type 获取变量的类型,然后与字符串的 nil 进行比较
1.6 function
function类型是由C或Lua编写的完成某一功能的程序指令的集合,称为函数,可分为自定义函数和系统函数。
function sum(a, b) |
1.7 thread
thread类型表示执行的独立线路,用于执行协同程序。
function fun() |
1.8 userdata
userdata类型是一种用户自定义数据,用于表示一种由应用程序或C/C++语言库所创建的类型,可以将任意C/C++的任意数据类型的数据存储在Lua变量中调用。
userdata可分为full userdata和light userdata。
full userdata | light userdata | |
---|---|---|
定义 | 用户自定义数据 | 一种表示C指针的值,不用创建 |
使用 | 需要显示的创建一块内存,该段内存有Lua垃圾回收器管理,不需要使用者关心 | 存储在栈上,使用者需要关心内存使用 |
创建 | 没有进行参数合法性检查void *lua_newuserdata(lua State *L, size_t size); 有进行参数合法性检查 void *lua_checkudata(lua State *L, int arg, const char *tname); | void lua_pushlightuserdata(lua_State *L, void *p); |
其他 | 可以指定其metatable和metamethods | 不可以指定其metatable和metamethods |
2. 注释
2.1 单行注释
-- 这是行注释 |
2.2 多行注释
--[[ |
3. 变量
变量相当于内存中一个数据存储空间的表示,通过变量名可以访问到变量的具体的值。
Lua的变量在定义时不需要指定明确的类型,而是会根据赋的默认值来断定变量的类型。
3.1 变量赋值
赋值是给已经定义的变量重新设置值的过程。
同时为多个变量赋值时:
当变量个数 > 值的个数时,按变量个数补足nil
当变量个数 < 值的个数时,多余的值会被忽略
a = 1 |
3.2 全局变量和局部变量
变量根据作用域可分为全局变量和局部变量,且用local
显式声明的变量为局部变量,其余全部为全局变量。
local a = 1024 |
3.3 类型转换
Lua中,除了table类型,其他任何类型的变量都可以通过tostring
函数转化为字符串类型。
能表示数字的字符串类型的变量可以通过tonumber
函数转化为数字类型。
a = 100 |
3.4 获取输入
使用io.read
函数获取用户输入。
可选参数:
格式 | 描述 |
---|---|
“*n” | 读取一个数字 |
“*a” | 从当前位置读取剩余的全部内容 |
"*l” | 读取下一行内容 |
10 | 读取指定数字的长度 |
local name = io.read() |
3.5 格式化输出
name = "lua" |
4. 循环控制
循环控制就是让程序满足一定的条件就一直循环的去执行,直到条件不满足,则跳出循环继续执行循环以外的语句。
4.1 while
while循环,当型循环,先判断条件,满足则执行循环,否则不进入循环。
-- 求和 |
4.2 repeat … until
repeat until循环,直到型循环,后判断条件,满足则跳出循环,不满足则进入循环,循环至少会执行1次。
-- 求和 |
4.3 for
如果循环的语句是for i = 1, 9, 1 do ...
,表示从1开始,大于9结束,每次步进1。如果是步进1,最后1可以省略,变为for i = 1, 9 do ...
。
-- 求和 |
4.4 break
终止循环的继续运行,如果有多层循环,只能终止当层循环,无法终止外层循环。
for i = 0, 1 do |
Lua中没有continue语句,但是可以借助for循环以及repeat until循环实现continue功能。
for i = 0, 4 do |
4.5 return
使用return语句,终止循环、函数的执行。
for i = 0, 5, 1 do |
4.6 goto
允许将控制流程无条件地转到被标记的语句处,仅lua5.2以上版本支持。
local a = 1 |
4.7 pairs和ipairs
pairs和iparis都是能遍历集合(表、数组),但是iparis仅仅遍历值,按照索引升序遍历,索引中断停止遍历,即不能返回nil,只能返回数字0,如果遇到nil则退出。只能遍历到集合中出现的第一个不是整数的key。pairs能遍历集合的所有元素。
local table = {"A", "B", [5] = "yes", ["t"] = "no"} |
5. 分支控制
分支控制就是让程序有选择的执行,主要分为:单分支、双分支和多分支形式。
5.1 if
local a = 10 |
5.2 else
local a = 10 |
5.3 elseif
local a = 5 |
5.4 条件嵌套
local a = 5 |
6. 函数
在程序中,编写函数的主要目的是将一个需要很多行代码的复杂问题分解为一系列简单的任务来解决,而且,同一个函数可以被多次调用,有助于代码重用。
6.1 function
function sum(a, b) |
6.2 多返回值
Lua中的函数可以不返回任何值,也可以返回一个值,也支持返回多个值。
function check_user(score) |
6.3 可变参数
函数参数的个数可以是任意的,可变参数使用...
来表示,若想要获取用户传入的所有的参数,可以使用arg
变量。
function sum(...) |
6.4 匿名函数
function test_func(tab, fun) |
6.5 闭包
闭包的主要作用:
- 简洁,不需要在不使用时生成对象,也不需要函数名
- 可以捕获外部变量形成不同的调用环境
function func() |
7. 运算符
7.1 算术运算符
算术运算符是对数值类型的变量进行运算的。
运算符 | 说明 | 范例 | 结果 |
---|---|---|---|
+ | 正号 | +3 | 3 |
- | 负号 | -4 | -3 |
+ | 加法运算 | 5 + 5 | 10 |
- | 减法运算 | 10 - 5 | 5 |
* | 乘法运算 | 5 * 2 | 10 |
/ | 除法运算 | 10 / 3 | 3.3 |
% | 取余运算 | 10 % 3 | 1 |
^ | 幂运算 | 2^3 | 8 |
a, b = -20, 3 |
7.2 关系运算符
关系运算符结果要么是真,要么是假。
运算符 | 说明 | 范例 | 结果 |
---|---|---|---|
== | 相等 | 4 == 3 | false |
~= | 不等于 | 4 ~= 3 | true |
< | 小于 | 4 < 3 | false |
> | 大于 | 4 > 3 | true |
<= | 小于等于 | 4 <= 3 | false |
>= | 大于等于 | 4 >= 3 | true |
a = 100 |
7.3 逻辑运算符
逻辑运算符用来连接多个条件,最终返回是true或false,使用逻辑运算符可以模拟三目运算符。
运算符 | 说明 | 范例 |
---|---|---|
and | 逻辑与 | A and B,如果A的值为假,则不会再计算B的值 |
or | 逻辑或 | A or B,如果A的值为真,则不会再计算B的值 |
not | 逻辑非 | not A |
local age = 40 |
7.4 其他运算符
运算符 | 说明 | 范例 |
---|---|---|
… | 连接运算符 | str1…str2 |
# | 获取字符串长度 | #str1 |
local str1 = "hello" |
8. 字符串
8.1 字符串函数
函数 | 描述 |
---|---|
upper(arg) | 字符串全部转为大写字母 |
lower(arg) | 字符串全部转为小写字母 |
sub(s, i, [,j]) | 截取字符串 |
gsub(mainString, findString, replaceString, num) | 在字符串中替换 |
dump(function) | 把函数序列化为字符串来保存 |
find(str, substr, [init, [end]]) | 在字符串中查找,存在返回具体位置,不存在返回nil |
reverse(arg) | 字符串反转 |
format(…) | 返回一个格式化字符串 |
char(arg) | 将整型数字转化为字符并连接 |
byte[arg[int,]] | byte转换字符为整数值 |
len(arg) | 计算字符串长度 |
rep(string, n) | 返回字符串string的n个拷贝 |
… | 连接两个字符串 |
gmatch(str, pattern) | 迭代器函数,每次调用返回一个查找到的子串 |
match(str, pattern, init) | 查找第一个配对的子串 |
8.1 大小写转换
string.upper(s)
用于将字符串中所有字母转化为大写。
string.lower(s)
用于将字符串中所有字母转化为小写。
str1 = "Hello Lua" |
8.2 字符串截取
string.sub(s, i [, j])
用于字符串截取,返回字符串s从第i个字符到第j个字符的子串。注意,字符串的第1个字符索引是1。
str1 = "Hello Lua" |
8.3 字符串替换
string.gsub(mainString, findString, replaceString, num)
用于字符串替换,num指定替换字符串的次数,默认全部替换。
str1 = "Hello world, Hello Lua" |
8.4 序列化与加载
string.dump(function)
用于将函数序列化为字符串,便于函数的保存与传输loadstring(str)
用于将序列化后的函数字符串反序列化加载为函数。
function sum(a, b) |
8.5 字符串查找
string.find(str, substr, [init, [end]])
用于在一个指定的目标字符串中搜素指定的内容,返回其具体位置,不存在返回nil,也支持使用正则匹配查找。
str1 = "Hello Lua" |
8.6 字符串反转
string.reverse(arg)
用于反转字符串。
str = "Hello Lua" |
8.7 格式化字符串
格式 | 描述 | 格式 | 描述 |
---|---|---|---|
%c | 接收数字,转化为字符 | %d,%i | 接收数字,转化为有符号整数 |
%o | 接收数字,转化为八进制数 | %u | 接收数字,转化为无符号整数 |
%x | 接收数字,转化为十六进制数,使用小写字母 | %X | 接收数字,转化为十六进制数,使用大写字母 |
%e | 接收数字,转化为科学计数法,使用小写字母e | %E | 接收数字,转化为科学计数法,使用大写字母E |
%f | 接收数字,转化为浮点数 | %g,%G | 接收数字,转化为%e,%f中较短格式 |
%q | 接收字符串,转化为可安全被Lua编译器读入的格式 | %s | 接收字符串,按给定参数格式化字符串 |
%+ | 表示其后的数字转义符将让正数显示正号 | %占位符 | 在后面指定了字串宽度时占位用 |
%对齐标识 | 在指定了字串宽度时, 默认为右对齐, 增加 - 号改为左对齐 | %宽度数值 | 占位宽度 |
%小数位数/字串裁切 | 数字保留位数,字符串做裁切 |
print(string.format("%c", 65)) |
8.8 数字与字符的转换
string.char(arg)
用于将整数转化为字符并连接。
string.byte(arg[,int])
用于将字符转化为整数并连接,int表示要转换的字符。
print(string.char(97, 98, 99)) |
8.9 字符串长度
string.len()
用于获取字符串长度,另外#
也可以获取字符串长度。
str1 = "ABC" |
8.10 字符串拷贝
string.rep(string, n)
用于将字符串拷贝n次。
str = "ABCD" |
8.11 字符串连接
字符串可以使用..
连接。
str1 = "hello" |
8.12 字符串匹配
string.gmatch(str, pattern)
是一个迭代器函数,每调用一次,返回一个在字符串str查找到的符合pattern描述的子串,如果没找到返回nil,也支持正则匹配。
string.match(str, pattern, init)
只找寻str中第一个配对,搜索起点可配置,也支持正则匹配。
for word in string.gmatch("Hello Lua", "%a+") do |
8.13 转义字符
转义字符 | 意义 | 转义字符 | 意义 |
---|---|---|---|
\a | 响铃 | \b | 退格,将当前位置移到前一列 |
\f | 换页,将当前位置移到下页开头 | \n | 换行,将当前位置移到下一行开头 |
\r | 回车,将当前位置移到本行开头 | \t | 水平制表,跳到下一个Tab位置 |
\v | 垂直制表 | \ | 代表一个反斜线字符 |
’ | 代表一个单引号字符 | " | 代表一个双引号字符 |
\0 | 空字符 | \ddd | 1到3位八进制数所代表的任意字符 |
\xhh | 1到2位十六进制数所代表的任意字符 |
9. Table
数组与表的类型都为table。
数组的语法为arrName = {element1, element2, ....}
,数组保存的一组数据类型可以不一致,数组的索引值是以1为起始的,也可以人为指定为0开始,如arrName = {[0]=element1, element2, ....}
。
表是一个 “关联数组”,表的索引可以是数字或者是字符串,所有索引值都需要用 [
和 ]
括起来;如果没有 [] 括起,则认为是字符串索引,可以认为,数组是索引为以0或1开始的连续数字的一种特殊的表,因此,表的一些增删改查行为函数也适用于数组。
操作 | 描述 |
---|---|
concat | 连接 |
insert | 插入 |
maxn | 最大key |
remove | 移除 |
sort | 升序排序 |
9.1 定义
#
后面直接加数组名可以获取数组的长度,如果设置了索引从0开始,则获取到的数组长度会比实际的长度少1。
#
后面直接加表名无法准确获取数组的长度,会在索引中断的地方停止计数,应该用循环遍历来获取正确长度。
-- 数组 |
9.2 遍历
-- 数组 |
9.3 连接
table.concat(table [, sep [, start [, end]]])
函数列出参数中指定table的数组部分从start位置到end位置的所有元素,元素键以指定分隔符sep隔开,start默认为1。注:该函数只处理table下标为数字的数据,且下标是连续的才能被处理,断开就结束了。
fruits = {"orange", "apple", "banana"} |
9.4 插入
table.insert(table [pos,] value)
函数在table指定位置pos插入一个value元素,pos默认为数组部分末尾,即连续下标元素的最后。
fruits = {"orange", "apple", "banana"} |
9.5 最大值
table.maxn(table)
函数返回table的最大正数索引,如果没有正数索引返回0。Lua5.2之后的版本已移除该函数。
fruits = {"orange", "apple", "banana"} |
9.6 删除
table.remove(table [,pos])
函数删除指定pos位置的元素,pos默认为table长度。即连续索引的最大值。
fruits = {"orange", "apple", "banana"} |
9.7 排序
table.sort(table [,comp])
函数用于对给定的table进行升序排序,还支持传入排序规则。
local test0 ={1,9,2,8,3,7,4,6} |
10. 元素metatable
10.1 定义
Lua的table中可以访问对应的key来得到value值,但是却无法对两个table进行操作。元表允许改变table的行为,每个行为关联了对应的元方法。如两个table相加操作a+b
,当Lua尝试对两个表相加时,先检查两者之一是否有元表,之后检查__add
字段是否存在,如果操作,则调用相应的值。__add
等即时字段其对应的值就是元方法。
有两个重要的函数处理元表:
函数 | 描述 |
---|---|
setmetatable(table, metatable) | 对指定的table设置元表,如果元表中存在__metatable 键值,则setmetatable会失败 |
getmetatable(table) | 返回对象的元表 |
mytable = {} -- 普通表 |
10.2 __index元方法
__index
元方法用来对表访问。
Lua查找一个表元素时的规则:
1 在表中查找,如果找到,返回该元素,找不到继续
2 判断该表是否有元表,如果没有元表,返回nil,有元表则继续
3 判断该表有没有__index
方法,如果__index
方法为nil,则返回nil,如果__index
方法是一个表,则重复1、2、3步;如果__index
方法是一个函数,则返回该函数的返回值
mytable = setmetatable({key1 = "value1"}, { |
10.3 __newindex元方法
__newindex
元方法用来对表更新。
当给表的一个缺少的索引赋值,解释器会查找__newindex
元方法,如果存在,则调用这个函数而不进行赋值操作。
mytable = setmetatable({key1 = "value1"}, { |
10.4 __call元方法
__call
元方法可以让table当做一个函数来使用。
local mt = {} |
10.5 __tostring元方法
__tostring
元方法用于修改表的输出行为。
mytable = setmetatable({10, 20, 30}, { |
10.6 为表添加操作符
模式 | 等价于运算符 | 模式 | 等价于运算符 |
---|---|---|---|
__add | + | __sub | - |
__mul | * | __div | / |
__mod | % | __unm | - |
__concat | … | __eq | == |
__lt | < | __le | <= |
function table_maxn(t) |
11. 模块与包
11.1 模块定义
模块类似于一个封装库,是由变量、函数等已知元素组成的table,因此创建模块就是创建一个table,然后把需要导出的常量、函数放入其中,最后返回这个table即可。如下创建自定义模块module。
-- 文件名 module.lua |
11.2 require函数
require("模块名")
用来加载模块,执行require后会返回一个由模块常量或函数组成的table,并且还会定义一个包含该table的全局变量。
require("module") |
require函数会尝试从Lua文件或C程序中加载模块,require用于搜索Lua文件的路径存放在全局变量package_path中,当Lua启动后,会以环境变量LUA_PATH的值来初始化这个环境变量,如果找不到该环境变量,则使用一个编译时定义的默认路径来初始化。
可以自定义设置路况,在当前用户跟目录下打开.profile文件(没有则创建,打开.bashrc文件也可以),例如把"~/lua/"路径加入LUA_PATH环境变量里。
#LUA_PATH |
文件路径以";“号分割,最后两个”;;"表示新加的路径后面加上原来的默认路径。
接着执行指令source ~/.profile
更新变量参数使之生效。
如果找到目标文件,则会调用package.loadfile
来加载模块,否则就会找C程序库。
搜索的文件路径是从全局变量 package.cpath 获取,而这个变量则是通过环境变量 LUA_CPATH 来初始。
搜索的策略跟上面的一样,只不过现在换成搜索的是 so 或 dll 类型的文件。如果找得到,那么 require 就会通过 package.loadlib 来加载它。
11.3 module函数
module()
函数调用时会创建表并将其赋予给全局变量和loaded table,最后还会将这个表设置为主程序块的环境。
-- 在模块文件在使用module函数 |
11.4 调用C语言包
Lua和C语言很容易结合,可以使用C语言为Lua写包,C语言包使用前必须先加载并连接,大多数系统是通过动态连接库机制。
Lua在一个加loadlib的函数内提供了所有的动态连接功能。这个函数的两个参数:库的绝对路径和初始化函数,如:
local path = "/usr/local/lua/lib/libluasocket.so" |
loadlib函数加载指定的库并连接到Lua,然而并没有调用初始化函数,而是返回初始化函数作为Lua的一个函数。
如果加载动态库或者查找初始化函数出错,loadlib将返回nil和错误信息。
local path = "C:\\windows\\luasocket.dll" |
一般情况下我们期望二进制的发布库包含一个与前面代码段相似的 stub 文件,安装二进制库的时候可以随便放在某个目录,只需要修改 stub 文件对应二进制库的实际路径即可。
将 stub 文件所在的目录加入到 LUA_PATH,这样设定后就可以使用 require 函数加载 C 库了。
12. 协程
12.1 定义
协程与线程比较类似,拥有独立的堆栈、独立的局部变量、独立的指令,同时又与其他协同程序共享全局变量和其他大部分东西。
一个具有多线程的程序可以同时运行几个线程,而协程却需要彼此写作运行,在任一指定时刻只有一个协程在运行,并且这个正在运行的协同程序只有在明确的被要求挂起时才会被挂起。
协程有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协程。
12.2 用法
方法 | 描述 |
---|---|
coroutine.create() | 创建coroutine,返回coroutine,参数是一个函数,当和resume配合使用时唤醒函数调用 |
coroutine.resume() | 重启coroutine,和create配合使用 |
coroutine.yield() | 挂起coroutine,将coroutine设置为挂起状态,和resume配合使用能够有很多效果 |
coroutine.status() | 查看coroutine的状态,有dead、suspened、running三种状态 |
coroutine.wrap() | 创建coroutine,返回一个函数,一旦调用这个函数,就进入croutine,和create功能重复 |
coroutine.running() | 返回正在运行的coroutine,一个coroutine就是一个新村,返回一个coroutine的线程号 |
function foo(a) |
12.3 生产者-消费者问题
local newProductor |
13. 文件IO
Lua文件IO库用于读取和处理文件,分为简单模式和完全模式:
- 简单模式:拥有一个当前输入文件和一个当前输出文件,并且提供针对这些文件相关的操作,适合做一些简单的文件操作
- 完全模式:使用外部的文件句柄来实现,以一种面向对象的形式,将所有的文件操作定义为文件句柄的方法,适合做一些高级的文件操作,如同时读取多个文件
13.1 简单模式
函数 | 描述 |
---|---|
io.input([file]) | 设置默认的输入文件,file为文件名,返回文件句柄 |
io.output([file]) | 设置默认的输出文件,file为文件名 |
io.close([file]) | 关闭文件,不带参数的默认文件 |
io.read(formats) | 读取默认文件,formats取值为a* -全读、*n -按数字读入、*l -按行读入,n -读取n个字符 |
io.lines([fn]) | fn文件名,如无文件,取默认文件,返回一个迭代器 |
io.write(value) | 向默认文件写入内容 |
io.flush() | 把文件缓存里的操作立即作用到默认输出文件 |
-- 以只读方式打开文件 |
13.2 完全模式
-- 以只读方式打开文件 |
14. 错误处理
错误类型分为语法错误和运行错误。
语法错误通常是对程序的组件使用不当引起,如:
for a = 1, 10 |
运行错误时程序可以正常运行,但是会输出报错信息,如:
function add(a, b) |
14.1 assert
assert(express, message)
断言函数会判断给定express表达式是否成立,成立的话不做任何事情,不成立则以message作为错误信息抛出。
function add(a, b) |
14.2 error
error(message [,level])
函数终止正在执行的函数,并返回message的内容作为错误信息,level参数指示获得错误的位置,level=1指出调用error位置,level=2指出调用error函数的函数吗,level=0不添加错误位置信息。
function add(a, b) |
14.3 pcall
可以使用pcall
函数包装需要执行的代码,pcall
函数接收一个函数和要传递给后者的参数,并执行该函数,无错误返回true,有错误返回false和错误信息。
a, errorinfo = pcall(function(i) print(i) end, 27) |
14.4 xpcall
xpcall
函数相比pcall
函数会返回更多的错误调试信息,并执行该函数,无错误返回true,有错误返回false和错误信息。
function myfunction () |
15. 垃圾回收
15.1 机制
Lua运行了一个垃圾收集器收集所有死对象来完成自动内存管理的工作。
Lua实现了一个增量标记-扫描收集器,使用垃圾收集器间歇率和垃圾收集器步进倍率来控制垃圾收集循环。
垃圾收集器间歇率控制着收集器需要在开启新的循环前要等待多久。
垃圾收集器步进倍率控制收集器运作速度相对与内存分配速度的倍率,默认值是200%,即运作速度2倍于内存分配速率。
15.2 垃圾回收器函数
Lua提供一下函数collectgarbage([opt [,arg]])
来控制自动内存管理。
函数 | 功能 |
---|---|
collectgarbage(“collect”) | 做一次完整的垃圾收集循环 |
collectgarbage(“count”) | 以K字节数为单位返回Lua使用的总内存数 |
collectgarbage(“restart”) | 重启垃圾收集器的自动运行 |
collectgarbage(“setpause”) | 将arg设为收集器的间歇率,返回间歇率的前一个值 |
collectgarbage(“setstepmul”) | 返回步进倍率的前一个值 |
collectgarbage(“step”) | 单步运行垃圾收集器,步长由arg控制 |
collectgarbage(“stop”) | 停止垃圾收集器的运行 |
mytable = {"apple", "orange", "banana"} |
16. 面向对象
16.1 面向对象特征
封装:能够把一个实体的信息、功能、响应都装入一个单独的对象中的特征。
继承:基础的方法允许在不改动原程序的基础上对其进行扩充,使得原功能得以保存,新功能也得以扩展,有利于减少重复代码,提高开发效率。
多态:同一操作作用于不同的对象,产生不同的执行结果,可以通过指向基类的指针,来调用实现派生类的方法。
抽象:简化复杂问题的方法,可以为具体问题找到最恰当的类定义,并且可以在最恰当的继承级别解释问题。
16.2 类封装
-- 元类 |
16.3 继承与多态
-- 元类 |
参考文章
本文是笔者通过下列网站教程学习Lua的记录,有部分修改和补充,转载请注明出处,并附带下面链接。