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 中还定义了很多的内置全局变量,这些内置全局变量的一个共同特征是,以下划线开头后跟全大写字母。所以我们在定义自己的标识符时不能与这些保留字、内置全局变量重复。

andbreakdoelse
elseifendfalsefor
functionifinlocal
nilnotorrepeat
returnthentrueuntil
whilegoto

运算符

下表列出了 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 语句的判断条件可以使用小括号括起来,也可以不使用。

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

循环

while···do
a=3
while a>0 do
	print(a)
	a=a-1
end
repeat···until
-- 类似do···while
a=3
repeat
	print(a)
	a=a-1
until a<=0
数值for
-- 第一个参数是初始值;第二个是比较值;第三个是步长。不指定步长就为1。
for i=10,50,20 do
    print(i)
end

for i=1,3 do
    print(i)
end
泛型for

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

函数

1. 固定参数函数
function f(x,y)
    print(x,y)
end

f()
f(1)
f(1,2)
f(1,2,3)

运行结果:

nil     nil
1       nil
1       2
1       2
2. 可变参函数
function f(...)
    print(...)
end

f()
f(1)
f(1,2)
f(1,2,3)

运行结果:

1
1       2
1       2       3
3. 多返回值
function f(...)
    return ...
end

a=f()
b=f(1)
c,d=f(1,2)
e,f,g=f(1,2,3)

print(a,b,c,d,e,f,g)

运行结果:

nil     1       1       2       1       2       3
4. 函数作参数
function add( x,y )
    return(x+y)
end

function sub( x,y )
    return(y-x)
end

function f(m,n,fun)
    result=fun(m,n)
    print(result)
end

f(1,2,add)
f(1,2,sub)

运行结果:

3
1
5.匿名函数
function f(m,n,fun)
    result=fun(m,n)
    print(result)
end

-- 匿名函数调用
f( 3, 5,function(a,b)
    return a*b
    end
 )

运行结果:

15

Lua 语法进阶

table

1. 数组

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

-- 一维数组
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
    end
end

for i = 1, 3 do
    for j = 1, 2 do
        print(array[i][j])
    end
end

运行结果:

banana
orange
apple
2
3
3
4
4
5
2. map

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

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=3
c=4

m={
    [a.."bbb"]=true,
    [b+c]=7
}
print(m.aaa_bbb)
print(m[7])

运行结果:

销售部
bing
123
18
true
7
3. 数组-map 混合结构

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

msg={"北京",name="bing",age=18,"上海",gender="男","广州"}

for i=1,3 do
    print(msg[i])
end

运行结果:

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

运行结果:

张三 : 20
李四 : 21
王五 : 22
4. table操作函数

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

  • table.concat()

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

    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))
    

    运行结果:

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

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

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

    运行结果:

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

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

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

    运行结果:

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

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

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

    运行结果:

    4
    
  • table.insert()

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

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

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

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

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

    注意:

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

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

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

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

    运行结果:

    1,2,4,6,7,9
    9,7,6,4,2,1
    

迭代器

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

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

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

msg={"北京",name="bing","深圳",age=18,"上海",gender="男","广州"}

-- 迭代数组元素
for i,v in ipairs(msg) do
    print(i,v)
end

运行结果:

1       北京
2       深圳
3       上海
4       广州
msg={"北京",name="bing","深圳",age=18,"上海",gender="男","广州"}

-- 迭代所有元素
for k,v in pairs(msg) do
    print(k,v)
end

运行结果:

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

模块

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

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

-- myModule.lua
-- 申明一个模块
local myModule = {}

-- 为模块添加一个变量
myModule.pi = 3.14

-- 为模块添加一个函数 (求矩形周长)
function myModule.perimeter(a, b)
        return (a + b) * 2
end

-- 为模块添加一个匿名函数 (求矩形面积)
myModule.area = function(a, b)
        return a * b
end

--=============== 定义一些与模块无关的内容 ===============--
-- 定义一个全局变量
goldenRatio = 0.618

-- 定义一个局部函数 (求圆的面积)(外部不能使用模块内部的局部变量和函数)
local function circleArea(r)
        return myModule.pi * r * r
end

-- 定义一个全局函数 (求矩形中最大圆的面积)
function maxArea(a, b)
        local r = math.min(a, b)
        return circleArea(r)
end

return myModule
-- test.lua
local myModule = require "myModule"

print(myModule.pi)
print(myModule.perimeter(3,5))
print(myModule.area(3,5))

print(goldenRatio)
print(maxArea(3,5))

运行结果:

[root@centos StudyLua]# lua test.lua
3.14
16
15
0.618
28.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。

msg={"北京",nil,name="bing","深圳",age=18,"上海",gender="男","广州"}

-- 返回nil
print(msg.xxx)

-- 声明一个元表
meta={}

-- 将msg与原表(meta)关联起来
setmetatable(msg, meta)

-- 重写__index方法
meta.__index=function(tab,key)
    return "通过【"..key.."】访问的值不存在"
end

print(msg.xxx)
print(msg[2])

运行结果:

nil
通过【xxx】访问的值不存在
通过【2】访问的值不存在
msg={"北京",nil,name="bing","深圳",age=18,"上海",gender="男","广州"}

-- 声明一个元表
meta={}

-- 将msg与原表(meta)关联起来
setmetatable(msg, meta)

-- 定义另一个表
other={}

other[6]="江西"
other.xxx="湖北"

-- 重写__index方法
-- 如果在msg中找不到相关信息,则会去other表中查找
meta.__index=other

print(msg[6])
print(msg.xxx)

运行结果:

江西
湖北
3. __newindex元方法

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

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)
end

msg.xxx="江西"
print(msg.xxx)
msg[6]="湖北"
print(msg[6])

运行结果:

新增的key为: xxx   新增的value为: 江西
江西
新增的key为: 6   新增的value为: 湖北
湖北
msg={"北京",nil,name="bing","深圳",age=18,"上海",gender="男","广州"}

-- 声明一个元表
meta={}

-- 将msg与原表(meta)关联起来
setmetatable(msg, meta)

-- 定义另一个表
other={}

-- 重写__index方法
-- 会将新增的数据写入other这个table中
meta.__newindex=other

msg.xxx="江西"
print(msg.xxx)
print(other.xxx)

运行结果:

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字符串长度,#
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+3
for key,value in pairs(msg) do
    print("key: "..key.."   value: "..value)
end

运行结果:

key: 1   value: 北京3
key: 2   value: 20
key: 3   value: 深圳3
key: 4   value: 上海3
key: 5   value: 广州3
key: gender   value: 男3
key: age   value: 21
key: name   value: bing3
5. __tostring 元方法

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

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)

运行结果:

1:北京 2:17 3:深圳 4:上海 5:广州 gender:男 name:bing age:18
6. __call 元方法

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

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)

运行结果:

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

面向对象

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

封装和继承
-- 创建一个学生类
Student = {}

-- 定义学生类的构造函数
function Student:new(name, age, gender)
    local obj = {
        name = name,
        age = age,
        gender = gender
    }
    -- 将对象的属性保存在obj中,并将obj设置为对象的元表。这样,当我们访问对象的属性时,可以通过元表的__index字段来查找。
    setmetatable(obj, { __index = self })
    return obj
end

-- 定义学生类的方法
function Student:getName()
    return self.name
end

function Student:getAge()
    return self.age
end

function Student:getGender()
    return self.gender
end

-- 创建一个研究生类
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 obj
end

-- 定义研究生类的方法
function GraduateStudent:getMajor()
    return self.major
end

-- 创建学生对象
local student1 = Student:new("Alice", 18, "Female")

-- 创建研究生对象
local graduateStudent = GraduateStudent:new("Bob", 20, "Male", "Computer Science")

-- 调用学生对象的方法
print(student1:getName())    -- 输出:Alice
print(student1:getAge())     -- 输出:18
print(student1:getGender())  -- 输出:Female

-- 调用研究生对象的方法
print(graduateStudent:getName())     -- 输出:Bob
print(graduateStudent:getAge())      -- 输出:20
print(graduateStudent:getGender())   -- 输出:Male
print(graduateStudent:getMajor())    -- 输出:Computer Science

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

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

运行结果:

Alice
18
Female
Bob
20
Male
Computer 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 类型。一旦调用该函数就会创建并执行一个协同线程实例
-- 创建一个协同线程的实例
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))

运行结果:

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

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

-- 创建一个协同函数的实例
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)

运行结果:

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. 常用静态函数
-- 以只读方式打开一个文件
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)

运行结果:

name=bing
age=18
-- 以读写方式打开文件
file=io.open("info.txt","a+")

-- 指定写入的文件
io.output(file)

-- 写入数据
io.write("gender=male\n")

-- 关闭文件
io.close(file)

运行结果:

[root@centos StudyLua]# lua test.lua
[root@centos StudyLua]# cat info.txt
name=bing
age=18
gender=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:表示将指针定位到文件结尾处

-- 以只读的方式打开文件
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

-- 设置指针的位置为10
pos=file:seek("set",10)
-- 读取一行数据
line=file:read("*l")
print(line) -- 90

-- 设置指针到文件的末尾
pos=file:seek("end")
print(pos) -- 13

-- 关闭文件
file:close()

运行结果:

[root@centos StudyLua]# cat nums.txt
12345
67
890
[root@centos StudyLua]# lua test.lua
0
12345
6
0
90
13
  • 10
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值