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 语句的判断条件可以使用小括号括起来,也可以不使用。
-- demoa=5if a>0 then print("num>0")elseif a==0 then print("num=0")else print("num<0")end循环
while···do
a=3while a>0 do print(a) a=a-1endrepeat···until
-- 类似do···whilea=3repeat print(a) a=a-1until a<=0数值 for
-- 第一个参数是初始值;第二个是比较值;第三个是步长。不指定步长就为1。for i=10,50,20 do print(i)endfor i=1,3 do print(i)end泛型 for
详见:Lua 语法进阶—迭代器中的 for 循环。
函数
1. 固定参数函数
function f(x,y) print(x,y)endf()f(1)f(1,2)f(1,2,3)运行结果:
nil nil1 nil1 21 22. 可变参函数
function f(...) print(...)endf()f(1)f(1,2)f(1,2,3)运行结果:
11 21 2 33. 多返回值
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)运行结果:
nil 1 1 2 1 2 34. 函数作参数
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)运行结果:
315.匿名函数
function f(m,n,fun) result=fun(m,n) print(result)end-- 匿名函数调用f( 3, 5,function(a,b) return a*b end )运行结果:
15Lua 语法进阶
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 endendfor i = 1, 3 do for j = 1, 2 do print(array[i][j]) endend运行结果:
bananaorangeapple2334452. 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=3c=4m={ [a.."bbb"]=true, [b+c]=7}print(m.aaa_bbb)print(m[7])运行结果:
销售部bing12318true73. 数组-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王五 : 224. table 操作函数
Lua 中提供了对 table 进行操作的函数。
-
table.concat()
table.concat (table , sep , start , end)该函数用于将指定的 table 数组元素进行字符串连接。连接从 start 索引位置到 end 索引位置的所有数组元素, 元素间使用指定的分隔符 sep 隔开。如果 table 是一个混合结构,那么这个连接与 key-value 无关,仅是连接数组元素。
luamsg={"北京",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 不支持该函数。
luamsg={"北京","上海","广州","深圳"}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 不支持该函数。
luatmp=table.pack("banana","orange","apple")print(tmp.n)print(table.concat(tmp,","))运行结果:
text3banana,orange,apple -
table.maxn()
table.maxn(table)该函数返回指定 table 的数组中的最大索引值,即数组包含元素的个数。Lua 5.2 及以上版本中,table.maxn()函数已被废弃,不再被支持。
luamsg={"北京","上海","广州","深圳"}print(#msg)-- 下面的方式被弃用-- print(table.maxn(msg))运行结果:
text4 -
table.insert()
table.insert (table, [pos],value)。该函数用于在指定 table 的数组部分指定位置 pos 插入值为 value 的一个元素。其后的元素会被后移。pos 参数可选,默认为数组部分末尾。
luamsg = {"北京", "上海", "广州"}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 参数可选,默认删除数组中的最后一个元素。
luamsg = {"北京","江西","上海","广州","深圳"}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,则排序会报错。
luamsg = {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, ","))运行结果:
text1,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。
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 18gender 男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) * 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-- test.lualocal 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.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。
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])运行结果:
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=otherprint(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)endmsg.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=othermsg.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+3for key,value in pairs(msg) do print("key: "..key.." value: "..value)end运行结果:
key: 1 value: 北京3key: 2 value: 20key: 3 value: 深圳3key: 4 value: 上海3key: 5 value: 广州3key: gender value: 男3key: age value: 21key: name value: bing35. __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:186. __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 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 元方法设置为学生类本身。在构造函数中,我们还初始化了学生对象的属性。接下来,我们定义了一些用于访问学生对象属性的方法,例如 getName、getAge 和 getGender。这些方法可以通过对象的冒号语法进行调用。
然后将研究生类的元表设置为学生类,这样研究生对象就可以继承学生对象的方法。然后,在研究生类的构造函数中,我们调用了父类的构造函数,并添加了研究生类特有的属性。对于研究生对象,除了继承学生对象的属性和方法外,我们还可以调用 getMajor 方法来获取研究生特有的属性。
运行结果:
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 类型。一旦调用该函数就会创建并执行一个协同线程实例 |
-- 创建一个协同线程的实例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协同线程重新返回了协同线程的状态: dead2. 协同函数
协同线程可以单独创建执行,也可以通过协同函数的调用启动执行。使用 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=bingage=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.txtname=bingage=18gender=male2. 常用实例函数
-
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-- 设置指针的位置为10pos=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.txt1234567890[root@centos StudyLua]# lua test.lua012345609013