前言
本文小新为大家带来 Lua 语法进阶 相关知识,具体内容包括table
,迭代器
,模块
,元表与元方法
,面向对象
,协同线程与协同函数
,文件 IO
等进行详尽介绍~
不积跬步,无以至千里;不积小流,无以成江海。每天进步一点点,在成为强者的路上,小新与大家共同成长!
📌博主主页:小新要变强 的主页
👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~
👉Java微服务开源项目可参考:企业级Java微服务开源项目(开源框架,用于学习、毕设、公司项目、私活等,减少开发工作,让您只关注业务!)
🚩欢迎关注小新的Git仓库:小新Java成长之路,不定期更新Java学习资料~
↩️本文上接:超详细Redis入门教程——Lua 脚本简介与基础语法
目录
1️⃣table
🍀(1)数组
使用 table 可以定义一维、二维、多维数组。不过,需要注意,Lua 中的数组索引是从 1 开始的,且无需声明数组长度,可以随时增加元素。当然,同一数组中的元素可以是任意类型。
🍀(2)map
使用 table 也可以定义出类似 map 的 key-value 数据结构。其可以定义 table 时直接指定 key-value,也可单独指定 key-value。而访问时,一般都是通过 table 的 key 直接访问,也可以数组索引方式来访问,此时的 key 即为索引。
🍀(3)混合结构
Lua 允许将数组与 key-value 混合在同一个 table 中进行定义。key-value 不会占用数组的数字索引值。
🍀(4)table 操作函数
Lua 中提供了对 table 进行操作的函数。
A、 table.concat()
【函数】table.concat (table [, sep [, start [, end]]]):
【解析】该函数用于将指定的 table 数组元素进行字符串连接。连接从 start 索引位置到 end 索引位置的所有数组元素, 元素间使用指定的分隔符 sep 隔开。如果 table 是一个混合结构,那么这个连接与 key-value 无关,仅是连接数组元素。
B、 table.unpack()
【函数】table.unpack (table [, i [, j]])
【解析】拆包。该函数返回指定 table 的数组中的从第 i 个元素到第 j 个元素值。i 与 j 是可选的,默认 i 为 1,j 为数组的最后一个元素。Lua5.1 不支持该函数。
C、 table.pack()
【函数】table.pack (…)
【解析】打包。该函数的参数是一个可变参,其可将指定的参数打包为一个 table 返回。这个返回的 table 中具有一个属性 n,用于表示该 table 包含的元素个数。Lua5.1 不支持该函数。
D、 table.maxn()
【函数】table.maxn(table)
【解析】该函数返回指定 table 的数组中的最大索引值,即数组包含元素的个数。
E、 table.insert()
【函数】table.insert (table, [pos,] value):
【解析】该函数用于在指定 table 的数组部分指定位置 pos 插入值为 value 的一个元素。其后的元素会被后移。pos 参数可选,默认为数组部分末尾。
F、 table.remove ()
【函数】table.remove (table [, pos])
【解析】该函数用于删除并返回指定 table 中数组部分位于 pos 位置的元素。其后的元素会被前移。pos 参数可选,默认删除数组中的最后一个元素。
G、 table.sort()
【函数】table.sort(table [,fun(a,b)])
【解析】该函数用于对指定的 table 的数组元素进行升序排序,也可按照指定函数 fun(a,b) 中指定的规则进行排序。fun(a,b)是一个用于比较 a 与 b 的函数,a 与 b 分别代表数组中的两个相邻元素。
注意:
- 如果 arr 中的元素既有字符串又有数值型,那么对其进行排序会报错。
- 如果数组中多个元素相同,则其相同的多个元素的排序结果不确定,即这些元素的索引谁排前谁排后,不确定。
- 如果数组元素中包含 nil,则排序会报错。
2️⃣迭代器
Lua 提供了两个迭代器 pairs(table)与 ipairs(table)。这两个迭代器通常会应用于泛型 for 循环中,用于遍历指定的 table。这两个迭代器的不同是:
- ipairs(table):仅会迭代指定 table 中的数组元素。
- pairs(table):会迭代整个 table 元素,无论是数组元素,还是 key-value。
3️⃣模块
模块是 Lua中特有的一种数据结构。从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。
模块文件主要由 table 组成。在 table 中添加相应的变量、函数,最后文件返回该 table 即可。如果其它文件中需要使用该模块,只需通过 require 将该模块导入即可。
🍀(1)定义一个模块
模块是一个 lua 文件,其中会包含一个 table。一般情况下该文件名与该 table 名称相同,但其并不是必须的。
🍀(2)使用模块
这里要用到一个函数 require(“文件路径”),其中文件名是不能写.lua 扩展名的。该函数可以将指定的 lua 文件静态导入(合并为一个文件)。不过需要注意的是,该函数的使用可以省略小括号,写为 require “文件路径”。
require()函数是有返回值的,返回的就是模块文件最后 return 的 table。可以使用一个变量接收该 table 值作为模块的别名,就可以使用别名来访问模块了。
🍀(3)再看模块
模块文件中一般定义的变量与函数都是模块 table 相关内容,但也可以定义其它与 table 无关的内容。这些全局变量与函数就是普通的全局变量与函数,与模块无关,但会随着模块的导入而同时导入。所以在使用时可以直接使用,而无需也不能添加模块名称。
4️⃣元表与元方法
元表,即 Lua 中普通 table 的元数据表,而元方法则是元表中定义的普通表的默认行为。
Lua 中的每个普通 table 都可为其定义一个元表,用于扩展该普通 table 的行为功能。例如,对于 table 与数值相加的行为,Lua 中是没有定义的,但用户可通过为其指定元表来扩展这种行为;再如,用户访问不存在的 table 元素,Lua 默认返回的是 nil,但用户可能并不知道发生了什么。此时可以通过为该 table 指定元表来扩展该行为:给用户提示信息,并返回用户指定的值。
🍀(1)重要函数
元表中有两个重要函数:
- setmetatable(table,metatable):将 metatable 指定为普通表 table 的元表。
- getmetatable(table):获取指定普通表 table 的元表。
🍀(2)_ _index 元方法
当用户在对 table 进行读取访问时,如果访问的数组索引或 key 不存在,那么系统就会自动调用元表的_ index 元方法。该重写的方法可以是一个函数,也可以是另一个表。如果重写的 _index 元方法是函数,且有返回值,则直接返回;如果没有返回值,则返回 nil。
🍀(3) _ _newindex 元方法
当用户为 table 中一个不存在的索引或 key 赋值时,就会自动调用元表的_ newindex 元方法。该重写的方法可以是一个函数,也可以是另一个表。如果重写的 _newindex 元方法是函数,且有返回值,则直接返回;如果没有返回值,则返回 nil。
🍀(4)运算符元方法
如果要为一个表扩展加号(+)、减号(-)、等于(==)、小于(<)等运算功能,则可重写相应的元方法。
例如,如果要为一个 table 扩展加号(+)运算功能,则可重写该 table 元表的_ add 元方法,而具体的运算规则,则是定义在该重写的元方法中的。这样,当一个 table 在进行加法
(+)运算时,就会自动调用其元表的 _add 元方法。
类似于加法操作的其它操作,Lua 中还包含很多:
元方法 | 说明 |
---|---|
__add | 加法,+ |
__sub | 减法,- |
__mul | 乘法,* |
__div | 除法,/ |
__mod | 取模,% |
__pow | 次幂,^ |
__unm | 取反,- |
__idiv | 取整除法,// |
__concat | 字符串连接,… |
__len | 字符串长度,# |
__band | 按位与,& |
__bor | 按位或, |
__bxor | 按位异或,~ |
__bnot | 按位非,~ |
__shl | 按位左移,<< |
__shr | 按位右移,>> |
__eq | 等于,== |
__lt | 小于,< |
__le | 小于等于,<= |
🍀(5)_ _tostring 元方法
直接输出一个 table,其输出的内容为类型与 table 的存放地址。如果想让其输出 table 中的内容,可重写_ _tostring 元方法。
🍀(6)_ _call 元方法
当将一个 table 以函数形式来使用时,系统会自动调用重写的_ _call 元方法。该用法主要是可以简化对 table 的相关操作,将对 table 的操作与函数直接相结合。
🍀(7)元表单独定义
为了便于管理与复用,可以将元素单独定义为一个文件。该文件中仅可定义一个元表,且一般文件名与元表名称相同。
若一个文件要使用其它文件中定义的元表,只需使用 require “元表文件名”即可将元表导入使用。
如果用户想扩展该元表而又不想修改元表文件,则可在用户自己文件中重写其相应功能的元方法即可。
5️⃣面向对象
Lua 中没有类的概念,但通过 table、function 与元表可以模拟和构造出具有类这样功能的结构。
🍀(1)简单对象的创建
Lua 中通过 table 与 fcuntion 可以创建出一个简单的 Lua 对象:table 为 Lua 对象赋予属性,通过 function 为 Lua 对象赋予行为,即方法。
🍀(2)类的创建
Lua 中使用 table、function 与元表可以定义出类:使用一个表作为基础类,使用一个 function 作为该基础类的 new()方法。在该 new()方法中创建一个空表,再为该空表指定一个元表。该元表重写_ index 元方法,且将基础表指定为重写的 _index 元方法。由于 new() 中的表是空表,所以用户访问的所有 key 都会从基础类(表)中查找。
6️⃣协同线程与协同函数
🍀(1)协同线程
Lua 中有一种特殊的线程,称为 coroutine,协同线程,简称协程。其可以在运行时暂停执行,然后转去执行其它线程,然后还可返回再继续执行没有执行完毕的内容。即可以“走走停停,停停再走走”。
协同线程也称为协作多线程,在 Lua 中表示独立的执行线程。任意时刻只会有一个协程执行,而不会出现多个协程同时执行的情况。
协同线程的类型为 thread,其启动、暂停、重启等,都需要通过函数来控制。下表是用于控制协同线程的基本方法。
方法 | 描述 |
---|---|
create(function) | 创建一个协同线程实例,即返回的是 thread 类型。参数是一个 function。其需要通过 resume()来启动协同线程的执行 |
resume(thread, …) | 启动指定的协同线程的执行,使其从开始处或前面挂起处开始执行。可以向 create()的内置函数传递相应的参数。如果内置函数具有返回值,resume()会全部接收并返回。 |
running() | 返回正在运行的协同线程实例,即 thread 类型值 |
yield() | 挂起协同线程,并将协同线程设置为挂起状态。resume()可从挂起处重启被挂起的协同线程 |
status(thread) | 查看协同线程的状态。状态有三种:运行态 running,挂起态 suspended,消亡态 dead |
close() | 关闭协同线程 |
wrap(function) | 创建一个协同函数,返回的是 function 类型。一旦调用该函数就会创建并执行一个协同线程实例 |
🍀(2)协同函数
协同线程可以单独创建执行,也可以通过协同函数的调用启动执行。使用 coroutine 的 wrap()函数创建的就是协同函数,其类型为 function。
由于协同函数的本质就是函数,所以协同函数的调用方式就是标准的函数调用方式。只不过,协同函数的调用会启动其内置的协同线程。
7️⃣文件 IO
Lua 中提供了大量对文件进行 IO 操作的函数。这些函数分为两类:静态函数与实例函数。所谓静态函数是指通过 io.xxx()方式对文件进行操作的函数,而实例函数则是通过 Lua 中面向对象方式操作的函数。
🍀(1)常用静态函数
A、 io.open()
【格式】io.open (filename [, mode])
【解析】以指定模式打开指定文件,返回要打开文件的句柄,就是一个对象(后面会讲 Lua 中的对象)。其中模式 mode 有三种,但同时还可配合两个符号使用:
- r:只读,默认模式
- w:只写,写入内容会覆盖文件原有内容
- a:只写,以追加方式写入内容
- +:增加符,在 r+、w+、a+均变为了读写
- b:二进制表示符。如果要操作的文件为二进制文件,则需要变为 rb、wb、ab。
B、 io.input()
【格式】io.input (file)
【解析】指定要读取的文件。
C、 io.output()
【格式】io.output (file)
【解析】指定要写入的文件。
D、 io.read()
【格式】io.read([format])
【解析】以指定格式读取 io.input()中指定的输入文件。其中 format 格式有:
- *l:从当前位置的下一个位置开始读取整个行,默认格式
- *n:读取下一个数字,其将作为浮点数或整数
- *a:从当前位置的下一个位置开始读取整个文件
- number:这是一个数字,表示要读取的字符的个数
E、 io.write()
【格式】io.write(data)
【解析】将指定的数据 data 写入到 io.output()中指定的输出文件。
🍀(2)常用实例函数
A、 file:read()
这里的 file 使用的是 io.open()函数返回的 file,其实际就是 Lua 中的一个对象。其用法与 io.read()的相同。
B、 file:write()
用法与 io.write()的相同。
C、 file:seek()
【格式】file:seek ([whence [, offset]])
【解析】该函数用于获取或设置文件读写指针的当前位置。位置从 1 开始计数,除文件最后一行外,每行都有行结束符,其会占两个字符位置。位置 0 表示文件第一个位置的前面位置。
当 seek()为无参时会返回读写指针的当前位置。参数 whence 的值有三种,表示将指针定位的不同位置。而 offset 则表示相对于 whence 指定位置的偏移量,offset 的默认值为 0,为正表示向后偏移,为负表示向前偏移。
- set:表示将指针定位到文件开头处,即 0 位置处
- cur:表示指针保持当前位置不变,默认值
- end:表示将指针定位到文件结尾处
后记
👉Java全栈学习路线可参考:【Java全栈学习路线】最全的Java学习路线及知识清单,Java自学方向指引,内含最全Java全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/154087.html