前言

在这里插入图片描述

本文小新为大家带来 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全栈学习技术清单~
👉算法刷题路线可参考:算法刷题路线总结与相关资料分享,内含最详尽的算法刷题路线指南及相关资料分享~

更多推荐