Lua 脚本语法学习

标签:Redis首次发布:2024-03-25最近修改:2026-05-26

Lua 基础语法

单行注释和多行注释

两个减号是单行注释;由 --[[和 --]] 包裹起来的是多行注释。

lua
-- 单行注释--[[ 多行注释 多行注释 --]]

数据类型

数据类型 描述
nil 只有 nil 属于该类,表示一个无效值,与 Java 中的 null 类似。但在条件表达式中相当于 false
boolean 包含两个值:false 和 true。
number 表示双精度类型的实浮点数。
string 字符串,由一对双引号或单引号括起来。当一个字符串包含多行时,可以在第一行中以[[开头,在最后一行中以]]结尾,那么在[[与]]括起来的这多行内容就是一个字符串。换行符为字符串“\n”。
table 类似于 Java 中的数组,但比数组的功能更强大,更灵活。
function 由 C 或 Lua 编写的函数。
thread 协同线程,是协同函数的执行体,即正在执行的协同函数。
userdata 一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据存储到 Lua 变量中

标识符

程序设计语言中的标识符主要包含保留字、变量、常量、方法名、函数名、类名等。Lua 的标识符由字母、数字与下划线组成,但不能以数字开头。Lua 是大小写敏感的。

Lua 常见的保留字共有 22 个。不过,除了这 22 个外,Lua 中还定义了很多的内置全局变量,这些内置全局变量的一个共同特征是,以下划线开头后跟全大写字母。所以我们在定义自己的标识符时不能与这些保留字、内置全局变量重复。

and break do else
elseif end false for
function if in local
nil not or repeat
return then true until
while goto

运算符

下表列出了 Lua 语言中的常用算术运算符,设定 A 的值为 2,B 的值为 5:

操作符 描述 实例
+ 加法 A + B 输出结果 7
- 减法 A - B 输出结果 -3
* 乘法 A * B 输出结果 10
/ 除法 B / A 输出结果 2.5
% 取余 B % A 输出结果 1
^ 乘幂 A^2 输出结果 4
- 负号 -A 输出结果 -2
// 整除运算符(>=lua5.3) 5//2 输出结果 2

关系运算符

下表列出了 Lua 语言中的常用关系运算符,设定 A 的值为 10,B 的值为 20:

操作符 描述 实例
== 等于,检测两个值是否相等,相等返回 true,否则返回 false (A == B) 为 false。
~= 不等于,检测两个值是否相等,不相等返回 true,否则返回 false (A ~= B) 为 true。
> 大于,如果左边的值大于右边的值,返回 true,否则返回 false (A > B) 为 false。
< 小于,如果左边的值大于右边的值,返回 false,否则返回 true (A < B) 为 true。
>= 大于等于,如果左边的值大于等于右边的值,返回 true,否则返回 false (A >= B) 返回 false。
<= 小于等于, 如果左边的值小于等于右边的值,返回 true,否则返回 false (A <= B) 返回 true。

if 条件

Lua 提供了 if…then 用于表示条件判断,其中 if 的判断条件可以是任意表达式。Lua 系统将 false 与 nil 作为假,将 true 与非 nil 作为真,即使是 0 也是真

需要注意,Lua 中的 if 语句的判断条件可以使用小括号括起来,也可以不使用。

lua
-- demoa=5if a>0 then    print("num>0")elseif a==0 then    print("num=0")else    print("num<0")end

循环

while···do

lua
a=3while a>0 do    print(a)    a=a-1end

repeat···until

lua
-- 类似do···whilea=3repeat    print(a)    a=a-1until a<=0

数值 for

lua
-- 第一个参数是初始值;第二个是比较值;第三个是步长。不指定步长就为1。for i=10,50,20 do    print(i)endfor i=1,3 do    print(i)end

泛型 for

详见:Lua 语法进阶—迭代器中的 for 循环。

函数

1. 固定参数函数

lua
function f(x,y)    print(x,y)endf()f(1)f(1,2)f(1,2,3)

运行结果:

text
nil     nil1       nil1       21       2

2. 可变参函数

lua
function f(...)    print(...)endf()f(1)f(1,2)f(1,2,3)

运行结果:

text
11       21       2       3

3. 多返回值

lua
function f(...)    return ...enda=f()b=f(1)c,d=f(1,2)e,f,g=f(1,2,3)print(a,b,c,d,e,f,g)

运行结果:

text
nil     1       1       2       1       2       3

4. 函数作参数

lua
function add( x,y )    return(x+y)endfunction sub( x,y )    return(y-x)endfunction f(m,n,fun)    result=fun(m,n)    print(result)endf(1,2,add)f(1,2,sub)

运行结果:

text
31

5.匿名函数

lua
function f(m,n,fun)    result=fun(m,n)    print(result)end-- 匿名函数调用f( 3, 5,function(a,b)    return a*b    end )

运行结果:

text
15

Lua 语法进阶

table

1. 数组

使用 table 可以定义一维、二维、多维数组。不过,需要注意,Lua 中的数组索引是从 1开始的,且无需声明数组长度可以随时增加元素。当然,同一数组中的元素可以是任意类型

lua
-- 一维数组fruits = {"banana","orange","apple"}for i=1,3 do    print(fruits[i])end-- 二维数组(三行两列)array={}for i = 1, 3 do    array[i] = {}    for j = 1, 2 do        array[i][j] = i + j    endendfor i = 1, 3 do    for j = 1, 2 do        print(array[i][j])    endend

运行结果:

text
bananaorangeapple233445

2. map

使用 table 也可以定义出类似 map 的 key-value 数据结构。其可以定义 table 时直接指定 key-value,也可单独指定 key-value。而访问时,一般都是通过 table 的 key 直接访问,也可以数组索引方式来访问,此时的 key 即为索引。

lua
msg={name="bing",age=18,gender="男"}-- 通过下标操作msg["depart"]="销售部"print(msg["depart"])print(msg["name"])-- 通过.操作msg.password="123"print(msg.password)print(msg.age)-- 定义一个map key为表达式a="aaa_"b=3c=4m={    [a.."bbb"]=true,    [b+c]=7}print(m.aaa_bbb)print(m[7])

运行结果:

text
销售部bing12318true7

3. 数组-map 混合结构

Lua 允许将数组与 key-value 混合在同一个 table 中进行定义。key-value 不会占用数组的数字索引值。

lua
msg={"北京",name="bing",age=18,"上海",gender="男","广州"}for i=1,3 do    print(msg[i])end

运行结果:

text
北京上海广州
lua
students={    {name="张三",age=20},    {name="李四",age=21},    {name="王五",age=22}}for i=1,3 do    print(students[i].name.." : "..students[i].age)end

运行结果:

text
张三 : 20李四 : 21王五 : 22

4. table 操作函数

Lua 中提供了对 table 进行操作的函数。

  • table.concat()

    table.concat (table , sep , start , end)该函数用于将指定的 table 数组元素进行字符串连接。连接从 start 索引位置到 end 索引位置的所有数组元素, 元素间使用指定的分隔符 sep 隔开。如果 table 是一个混合结构,那么这个连接与 key-value 无关,仅是连接数组元素。

    lua
    msg={"北京",name="bing",age=18,"上海",gender="男","广州"}print(table.concat(msg))print(table.concat(msg,","))print(table.concat(msg,",",2))print(table.concat(msg,",",1,2))

    运行结果:

    text
    北京上海广州北京,上海,广州上海,广州北京,上海
  • table.unpack()

    table.unpack (table , i , j)拆包。该函数返回指定 table 的数组中的从第 i 个元素到第 j 个元素值。i 与 j 是可选的,默认 i 为 1,j 为数组的最后一个元素。Lua5.1 不支持该函数。

    lua
    msg={"北京","上海","广州","深圳"}print(table.unpack(msg))print(table.unpack(msg,2))print(table.unpack(msg,2,3))

    运行结果:

    text
    北京    上海    广州    深圳上海    广州    深圳上海    广州
  • table.pack()

    table.pack (…)打包。该函数的参数是一个可变参,其可将指定的参数打包为一个 table 返回。这个返回的 table 中具有一个属性 n,用于表示该 table 包含的元素个数。Lua5.1 不支持该函数。

    lua
    tmp=table.pack("banana","orange","apple")print(tmp.n)print(table.concat(tmp,","))

    运行结果:

    text
    3banana,orange,apple
  • table.maxn()

    table.maxn(table)该函数返回指定 table 的数组中的最大索引值,即数组包含元素的个数。Lua 5.2 及以上版本中,table.maxn()函数已被废弃,不再被支持。

    lua
    msg={"北京","上海","广州","深圳"}print(#msg)-- 下面的方式被弃用-- print(table.maxn(msg))

    运行结果:

    text
    4
  • table.insert()

    table.insert (table, [pos],value)。该函数用于在指定 table 的数组部分指定位置 pos 插入值为 value 的一个元素。其后的元素会被后移。pos 参数可选,默认为数组部分末尾。

    lua
    msg = {"北京", "上海", "广州"}table.insert(msg, "深圳")print(table.concat(msg, ","))table.insert(msg, 2, "江西")print(table.concat(msg, ","))

    运行结果:

    text
    北京,上海,广州,深圳北京,江西,上海,广州,深圳
  • table.remove ()

    table.remove (table,[pos])该函数用于删除并返回指定 table 中数组部分位于 pos 位置的元素。其后的元素会被前移。pos 参数可选,默认删除数组中的最后一个元素。

    lua
    msg = {"北京","江西","上海","广州","深圳"}table.remove(msg)print(table.concat(msg, ","))table.remove(msg, 2, "江西")print(table.concat(msg, ","))

    运行结果:

    text
    北京,江西,上海,广州北京,上海,广州
  • table.sort()

    table.sort(table , [fun(a,b)])。该函数用于对指定的 table 的数组元素进行升序排序,也可按照指定函数 fun(a,b)中指定的规则进行排序。fun(a,b)是一个用于比较 a 与 b 的函数,a 与 b 分别代表数组中的两个相邻元素。

    注意:

    • 如果 arr 中的元素既有字符串又有数值型,那么对其进行排序会报错。

    • 如果数组中多个元素相同,则其相同的多个元素的排序结果不确定,即这些元素的索引

    • 如果数组元素中包含 nil,则排序会报错。

    lua
    msg = {6, 2, 7, 4, 1, 9}-- 默认升序table.sort(msg)print(table.concat(msg, ","))-- 自定义排序函数实现降序table.sort(msg, function(a, b)    return a > bend)print(table.concat(msg, ","))

    运行结果:

    text
    1,2,4,6,7,99,7,6,4,2,1

迭代器

Lua 提供了两个迭代器 pairs(table)与 ipairs(table)。这两个迭代器通常会应用于泛型 for 循环中,用于遍历指定的 table。这两个迭代器的不同是:

  • ipairs(table):仅会迭代指定 table 中的数组元素。

  • pairs(table):会迭代整个 table 元素,无论是数组元素,还是 key-value。

lua
msg={"北京",name="bing","深圳",age=18,"上海",gender="男","广州"}-- 迭代数组元素for i,v in ipairs(msg) do    print(i,v)end

运行结果:

text
1       北京2       深圳3       上海4       广州
lua
msg={"北京",name="bing","深圳",age=18,"上海",gender="男","广州"}-- 迭代所有元素for k,v in pairs(msg) do    print(k,v)end

运行结果:

text
1       北京2       深圳3       上海4       广州age     18gender  男name    bing

模块

模块是 Lua 中特有的一种数据结构。从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。

模块文件主要由 table 组成。在 table 中添加相应的变量、函数,最后文件返回该 table 即可。如果其它文件中需要使用该模块,只需通过 require 将该模块导入即可。

lua
-- myModule.lua-- 申明一个模块local myModule = {}-- 为模块添加一个变量myModule.pi = 3.14-- 为模块添加一个函数 (求矩形周长)function myModule.perimeter(a, b)        return (a + b) * 2end-- 为模块添加一个匿名函数 (求矩形面积)myModule.area = function(a, b)    return a * bend--=============== 定义一些与模块无关的内容 ===============---- 定义一个全局变量goldenRatio = 0.618-- 定义一个局部函数 (求圆的面积)(外部不能使用模块内部的局部变量和函数)local function circleArea(r)    return myModule.pi * r * rend-- 定义一个全局函数 (求矩形中最大圆的面积)function maxArea(a, b)    local r = math.min(a, b)    return circleArea(r)endreturn myModule
lua
-- test.lualocal myModule = require "myModule"print(myModule.pi)print(myModule.perimeter(3,5))print(myModule.area(3,5))print(goldenRatio)print(maxArea(3,5))

运行结果:

text
[root@centos StudyLua]# lua test.lua3.1416150.61828.26

元表与元方法

元表,即 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。

lua
msg={"北京",nil,name="bing","深圳",age=18,"上海",gender="男","广州"}-- 返回nilprint(msg.xxx)-- 声明一个元表meta={}-- 将msg与原表(meta)关联起来setmetatable(msg, meta)-- 重写__index方法meta.__index=function(tab,key)    return "通过【"..key.."】访问的值不存在"endprint(msg.xxx)print(msg[2])

运行结果:

text
nil通过【xxx】访问的值不存在通过【2】访问的值不存在
lua
msg={"北京",nil,name="bing","深圳",age=18,"上海",gender="男","广州"}-- 声明一个元表meta={}-- 将msg与原表(meta)关联起来setmetatable(msg, meta)-- 定义另一个表other={}other[6]="江西"other.xxx="湖北"-- 重写__index方法-- 如果在msg中找不到相关信息,则会去other表中查找meta.__index=otherprint(msg[6])print(msg.xxx)

运行结果:

text
江西湖北

3. __newindex 元方法

当用户为 table 中一个不存在的索引或 key 赋值时,就会自动调用元表的 __newindex 元方法。该重写的方法可以是一个函数,也可以是另一个表。如果重写 __newindex 元方法是函数,且有返回值,则直接返回;如果没有返回值,则返回 nil。

lua
msg={"北京",nil,name="bing","深圳",age=18,"上海",gender="男","广州"}-- 声明一个元表meta={}-- 将msg与原表(meta)关联起来setmetatable(msg, meta)-- 重写__index方法meta.__newindex=function(tab,key,value)    print("新增的key为: "..key.."   新增的value为: "..value)    -- 将新增的key-value写入到原始表    rawset(tab,key,value)endmsg.xxx="江西"print(msg.xxx)msg[6]="湖北"print(msg[6])

运行结果:

text
新增的key为: xxx   新增的value为: 江西江西新增的key为: 6   新增的value为: 湖北湖北
lua
msg={"北京",nil,name="bing","深圳",age=18,"上海",gender="男","广州"}-- 声明一个元表meta={}-- 将msg与原表(meta)关联起来setmetatable(msg, meta)-- 定义另一个表other={}-- 重写__index方法-- 会将新增的数据写入other这个table中meta.__newindex=othermsg.xxx="江西"print(msg.xxx)print(other.xxx)

运行结果:

text
nil江西

4. 运算符元方法

如果要为一个表扩展加号(+)、减号(-)、等于(==)、小于(<)等运算功能,则可重写相应的元方法。例如,如果要为一个 table 扩展加号(+)运算功能,则可重写该 table 元表的__add 元方法,而具体的运算规则,则是定义在该重写的元方法中的。这样,当一个 table 在进行加法(+)运算时,就会自动调用其元表的__add 元方法。

元方法 说明 元方法 说明
__add 加法,+ __band 按位与,&
__sub 减法,- __bor 按位或,|
__mul 乘法,* __bxor 按位异或,~
__div 除法,/ __bnot 按位非,~
__mod 取模,% __shl 按位左移,<<
__pow 次幂,^ __shr 按位右移,>>
__unm 取反,-
__idiv 取整除法,// __eq 等于,==
__lt 小于,<
__concat 字符串连接,… __le 小于等于,<=
__len 字符串长度,#
lua
msg={"北京",17,name="bing","深圳",age=18,"上海",gender="男","广州"}-- 声明一个元表meta={    __add=function(tab,num)        -- 遍历table中的所有元素        for k,v in pairs(tab) do            if type(v)=="string" then                tab[k]=tab[k]..num            elseif type(v)=="number" then                tab[k]=tab[k]+num            end        end        -- 返回变化过的tab        return tab    end}-- 将msg与原表(meta)关联起来setmetatable(msg, meta)sumMsg=msg+3for key,value in pairs(msg) do    print("key: "..key.."   value: "..value)end

运行结果:

text
key: 1   value: 北京3key: 2   value: 20key: 3   value: 深圳3key: 4   value: 上海3key: 5   value: 广州3key: gender   value: 男3key: age   value: 21key: name   value: bing3

5. __tostring 元方法

直接输出一个 table,其输出的内容为类型与 table 的存放地址。如果想让其输出 table 中的内容,可重写 __tostring 元方法。

lua
msg={"北京",17,name="bing","深圳",age=18,"上海",gender="男","广州"}-- 声明一个元表meta={    __add=function(tab,num)        -- 遍历table中的所有元素        for k,v in pairs(tab) do            if type(v)=="string" then                tab[k]=tab[k]..num            elseif type(v)=="number" then                tab[k]=tab[k]+num            end        end        -- 返回变化过的tab        return tab    end, -- 当有多个元方法时,一定要用" , "隔开    __tostring=function(tab)        -- 做一个字符串拼接        str=""        for key,value in pairs(msg) do            str=str..key..":"..value.." "        end        return str    end}-- 将msg与原表(meta)关联起来setmetatable(msg, meta)-- 会输出table中的内容print(msg)

运行结果:

text
1:北京 2:17 3:深圳 4:上海 5:广州 gender:男 name:bing age:18

6. __call 元方法

当将一个 table 以函数形式来使用时,系统会自动调用重写的 __call 元方法。该用法主要是可以简化对 table 的相关操作,将对 table 的操作与函数直接相结合。

lua
msg={"北京",17,name="bing","深圳",age=18,"上海","广州"}-- 将msg与匿名元表关联起来setmetatable(msg, {    __tostring=function(tab)        -- 做一个字符串拼接        str=""        for key,value in pairs(msg) do            str=str..key..":"..value.." "        end        return str    end,    __call=function(tab,str,num)        -- 遍历table        for k,v in pairs(msg) do            if type(v)=="string" then                tab[k]=v..str            elseif type(v)=="number" then                tab[k]=v+num            end        end        return tab    end})msg("-hello",3)print(msg)

运行结果:

text
1:北京-hello 2:20 3:深圳-hello 4:上海-hello 5:广州-hello age:21 name:bing-hello

面向对象

Lua 中没有类的概念,但通过 table、function 与元表可以模拟和构造出具有类这样功能的结构。

封装和继承

lua
-- 创建一个学生类Student = {}-- 定义学生类的构造函数function Student:new(name, age, gender)    local obj = {        name = name,        age = age,        gender = gender    }    -- 将对象的属性保存在obj中,并将obj设置为对象的元表。这样,当我们访问对象的属性时,可以通过元表的__index字段来查找。    setmetatable(obj, { __index = self })    return objend-- 定义学生类的方法function Student:getName()    return self.nameendfunction Student:getAge()    return self.ageendfunction Student:getGender()    return self.genderend-- 创建一个研究生类GraduateStudent = {}-- 设置研究生类的元表为学生类,以实现继承setmetatable(GraduateStudent, { __index = Student })-- 定义研究生类的构造函数function GraduateStudent:new(name, age, gender, major)    local obj = Student:new(name, age, gender)  -- 调用父类的构造函数    obj.major = major  -- 添加研究生类特有的属性    setmetatable(obj, { __index = self })    return objend-- 定义研究生类的方法function GraduateStudent:getMajor()    return self.majorend-- 创建学生对象local student1 = Student:new("Alice", 18, "Female")-- 创建研究生对象local graduateStudent = GraduateStudent:new("Bob", 20, "Male", "Computer Science")-- 调用学生对象的方法print(student1:getName())    -- 输出:Aliceprint(student1:getAge())     -- 输出:18print(student1:getGender())  -- 输出:Female-- 调用研究生对象的方法print(graduateStudent:getName())     -- 输出:Bobprint(graduateStudent:getAge())      -- 输出:20print(graduateStudent:getGender())   -- 输出:Maleprint(graduateStudent:getMajor())    -- 输出:Computer Science

首先创建了一个空的 Student 表,它作为学生类的原型。然后,定义了一个 new 方法作为构造函数,用于创建学生对象。在构造函数中,我们使用 setmetatable 将新创建的对象(obj)与学生类关联起来,将元表的 __index 元方法设置为学生类本身。在构造函数中,我们还初始化了学生对象的属性。接下来,我们定义了一些用于访问学生对象属性的方法,例如 getNamegetAgegetGender。这些方法可以通过对象的冒号语法进行调用。

然后将研究生类的元表设置为学生类,这样研究生对象就可以继承学生对象的方法。然后,在研究生类的构造函数中,我们调用了父类的构造函数,并添加了研究生类特有的属性。对于研究生对象,除了继承学生对象的属性和方法外,我们还可以调用 getMajor 方法来获取研究生特有的属性。

运行结果:

text
Alice18FemaleBob20MaleComputer Science

协同线程与协同函数

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 类型。一旦调用该函数就会创建并执行一个协同线程实例
lua
-- 创建一个协同线程的实例co = coroutine.create(    function(a,b)        print(a+b,b-a)        -- 查看协同线程的类型        thread=coroutine.running()        print("协同线程的类型是: "..type(thread))        -- 查看协同线程的状态        print("协同线程的状态:",coroutine.status(co))        -- 挂起协同线程,并将返回值传递给主线程        coroutine.yield(a*b,b+1)        -- 当协同线程重新返回时会输出下面的语句        print("协同线程重新返回了")    end)-- 启动协同线程,等协同线程挂起的时候接收协同线程的返回值success,res1,res2=coroutine.resume(co,3,5)print("返回值:",success,res1,res2)-- 查看在主线程中co的状态print("协同线程的状态:",coroutine.status(co))-- 重新启动协同线程coroutine.resume(co)-- 最后查看协同线程的状态print("协同线程的状态:",coroutine.status(co))

运行结果:

text
8       2协同线程的类型是: thread协同线程的状态: running返回值: true    15      6协同线程的状态: suspended协同线程重新返回了协同线程的状态: dead

2. 协同函数

协同线程可以单独创建执行,也可以通过协同函数的调用启动执行。使用 coroutine 的 wrap()函数创建的就是协同函数,其类型为 function。由于协同函数的本质就是函数,所以协同函数的调用方式就是标准的函数调用方式。只不过,协同函数的调用会启动其内置的协同线程。

lua
-- 创建一个协同函数的实例cf = coroutine.wrap(    function(a,b)        print(a+b,b-a)        -- 挂起协同线程,并将返回值传递给主线程        coroutine.yield(a*b,b+1)        -- 当协同函数重新返回时会输出下面的语句        print("协同函数重新返回了")        return b/a    end)-- 启动协同函数,等协同函数挂起的时候接收协同函数的返回值res1,res2=cf(2,4)print("返回值:",res1,res2)-- 重新启动协同函数res=cf()print(res)

运行结果:

text
6       2返回值: 8       5协同函数重新返回了2.0

文件 IO

Lua 中提供了大量对文件进行 IO 操作的函数。这些函数分为两类:静态函数与实例函数。所谓静态函数是指通过 io.xxx()方式对文件进行操作的函数,而实例函数则是通过 Lua 中面向对象方式操作的函数。

  • io.open(filename , mode)

    其中,filename 是要打开的文件名,可以是相对路径或绝对路径。mode 是一个可选参数,用于指定打开文件的模式,默认为只读模式(“r”)。

    mode 参数可以是以下值之一:

    • "r":只读模式(默认值),打开文件用于读取。
    • "w":写入模式,打开文件用于写入。如果文件已存在,则清空文件内容;如果文件不存在,则创建新文件。
    • "a":追加模式,打开文件用于写入。如果文件已存在,则在文件末尾追加内容;如果文件不存在,则创建新文件。
    • "b":二进制模式,打开文件以二进制模式进行读取或写入。
    • "+":更新模式,打开文件用于读取和写入
  • io.input(file)

    指定要读取的文件。

  • io.output(file)

    指定要写入的文件。

  • io.read(format)

    以指定格式读取 io.input()中指定的输入文件。其中 format 格式有:

    • *l:从当前位置的下一个位置开始读取整个行,默认格式*
    • n:读取下一个数字,其将作为浮点数或整数
    • a:从当前位置的下一个位置开始读取整个文件
    • number:这是一个数字,表示要读取的字符的个数
  • io.write(data)

    将指定的数据 data 写入到 io.output()中指定的输出文件。

1. 常用静态函数

lua
-- 以只读方式打开一个文件file=io.open("info.txt","r")-- 指定要读取的文件io.input(file)-- 读取一行数据line=io.read("*l")while line ~= nil do    print(line)    line=io.read("*l")end-- 关闭文件io.close(file)

运行结果:

text
name=bingage=18
lua
-- 以读写方式打开文件file=io.open("info.txt","a+")-- 指定写入的文件io.output(file)-- 写入数据io.write("gender=male\n")-- 关闭文件io.close(file)

运行结果:

text
[root@centos StudyLua]# lua test.lua[root@centos StudyLua]# cat info.txtname=bingage=18gender=male

2. 常用实例函数

  • file:read()

    这里的 file 使用的是 io.open()函数返回的 file,其实际就是 Lua 中的一个对象。其用法与 io.read()的相同。

  • file:write()

    用法与 io.write()的相同。

  • file:seek(whence , offset)

    该函数用于获取或设置文件读写指针的当前位置。位置从 1 开始计数,除文件最后一行外,每行都有行结束符,其会占两个字符位置。位置 0 表示文件第一个位置的前面位置。当 seek()为无参时会返回读写指针的当前位置。参数 whence 的值有三种,表示将指针定位的不同位置。而 offset 则表示相对于 whence 指定位置的偏移量,offset 的默认值为 0,为正表示向后偏移,为负表示向前偏移。

    set:表示将指针定位到文件开头处,即 0 位置处

    cur:表示指针保持当前位置不变,默认值

    end:表示将指针定位到文件结尾处

lua
-- 以只读的方式打开文件file=io.open("nums.txt","r")-- 查看当前指针的位置pos=file:seek()print(pos) -- 0-- 读取一行数据line=file:read("*l")print(line) -- 12345-- 查看当前指针位置pos=file:seek()print(pos) -- 6-- 设置指针的位置到起始位置pos=file:seek("set")print(pos) -- 0-- 设置指针的位置为10pos=file:seek("set",10)-- 读取一行数据line=file:read("*l")print(line) -- 90-- 设置指针到文件的末尾pos=file:seek("end")print(pos) -- 13-- 关闭文件file:close()

运行结果:

text
[root@centos StudyLua]# cat nums.txt1234567890[root@centos StudyLua]# lua test.lua012345609013