Lua 脚本语法学习

news2024/12/28 22:43:23

文章目录

  • Lua 基础语法
    • 单行注释和多行注释
    • 数据类型
    • 标识符
    • 运算符
    • 关系运算符
    • if条件
    • 循环
      • while···do
      • repeat···until
      • 数值for
      • 泛型for
    • 函数
      • 1. 固定参数函数
      • 2. 可变参函数
      • 3. 多返回值
      • 4. 函数作参数
      • 5.匿名函数
  • Lua 语法进阶
    • table
      • 1. 数组
      • 2. map
      • 3. 数组-map 混合结构
      • 4. table操作函数
    • 迭代器
    • 模块
    • 元表与元方法
      • 1. 两个重要函数
      • 2. __index元方法
      • 3. __newindex元方法
      • 4. 运算符元方法
      • 5. __tostring 元方法
      • 6. __call 元方法
    • 面向对象
      • 封装和继承
    • 协同线程与协同函数
      • 1. 协同线程
      • 2. 协同函数
    • 文件IO
      • 1. 常用静态函数
      • 2. 常用实例函数

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

详见:迭代器中的for循环。

函数

1. 固定参数函数

function f(x,y)
    print(x,y)
end

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

image-20230614084016891

2. 可变参函数

function f(...)
    print(...)
end

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

image-20230614084621668

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)

image-20230614084836039

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)

image-20230614085630162

5.匿名函数

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

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

image-20230614090059340

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

image-20230614113205522

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

image-20230614161510477

3. 数组-map 混合结构

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

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

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

image-20230614162207486

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

image-20230614162702622

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

    image-20230614163513306

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

    image-20230614164132240

  • table.pack()

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

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

    image-20230614164739165

  • table.maxn()

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

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

    image-20230614165516339

  • 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, ","))
    

    image-20230614175018791

  • 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, ","))
    

    image-20230614175443607

  • 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, ","))
    

    image-20230614180119035

迭代器

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

image-20230614181053085

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

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

image-20230614181208477

模块

模块是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
-- demo1.lua
require "myModule"

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

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

image-20230615150600125

元表与元方法

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

image-20230615155803081

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)

image-20230615160336441

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

image-20230615161847102

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)

image-20230615162206220

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

image-20230615174724827

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)

image-20230615175920450

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)

image-20230616092948007

面向对象

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 方法来获取研究生特有的属性。

image-20230616111204977

协同线程与协同函数

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

image-20230616162710221

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)

image-20230616164410273

文件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. 常用静态函数

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

image-20230617095708371

-- demo3.lua
-- 以读写方式打开文件
file=io.open("info.txt","a+")

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

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

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

image-20230617101007205

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

image-20230617143027879

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/656339.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Makerbase SimpleFOC ESP32 例程9 在线电流检测测试

Makerbase SimpleFOC ESP32 例程9 在线电流检测测试 第一部分 硬件介绍 1.1 硬件清单 序号品名数量1 ESP32 FOC V1.0 主板 12 YT2804电机 23 12V电源适配器 14 USB 线 1 注意&#xff1a;YT2804是改装的云台无刷电机,带有AS5600编码器&#xff0c;可实现360连续运转。 主要…

java:实现用户扫码二维码自动跳转指定链接功能

0. 引言 近来接到要实现链接转二维码的需求&#xff0c;通过提供二维码给用户&#xff0c;让用户扫描后自动访问指定的H5页面&#xff0c;从而实现业务流转&#xff0c;这样的功能其实在其他很多场景也会用到&#xff0c;比如资产管理系统中&#xff0c;扫码资产二维码&#x…

uniapp实现tab切换可以滚动的效果

实现效果 当 tab 切换的内容很多时&#xff0c;需要用到滚动&#xff0c;希望在点击 tab 的时候可以自动滑动到对应的tab下 知识点 scrollIntoView&#xff1a;该scrollIntoView()方法将调用它的元素滚动到浏览器窗口的可见区域。 语法 element.scrollIntoView&#xff08…

2023 年企业 Java 面试前复习的正确姿势(已助力319人入职大厂)

作为 Java 程序员&#xff0c;选择学习什么样的技术&#xff1f;什么技术该不该学&#xff1f;去招聘网站上搜一搜、看看岗位要求就十分清楚了&#xff0c;自己具备的技术和能力&#xff0c;直接影响到你工作选择范围和能不能面试成功。 如果想进大厂&#xff0c;那就需要在 Ja…

ARM-Linux开发与MCU开发的不同之处分析

目录 一、ARM-Linux应用开发和单片机开发的不同 二、Arm-Linux基本开发环境 针对ARM-Linux程序的开发&#xff0c;主要分为三类&#xff1a;应用程序开发、驱动程序开发、系统内核开发。针对不同种类的软件开发&#xff0c;有其不同的特点。 今天&#xff0c;我们来看看ARM-L…

B-6:逆向分析及隐写

任务环境说明: 服务器场景: FTPServer20220509(关闭链接) FTP用户名:PE01密码: PE01 C语言:渗透机Windows7 (Embarcadero Dev-C++) 1,从靶机服务器的FTP上下载PE01文件,对PE01. exe二进制文件进行静态调试,将 main 函数的入口地址作为 Flag 值提交; 双击渗透机kali桌面上…

【数字图像处理】3.对比度增强

目录 3.1 灰度直方图 3.2 线性变换 3.3 直方图正规化 3.4 伽马变换 3.5 全局直方图均衡化 3.6 CLAHE 对比度增强是图像增强的一种&#xff0c;它主要解决的是图像的灰度级范围较小造成的对比度较低的问题&#xff0c;目的是将图像的灰度级增强到指定范围&#xff0c;使得…

Unity Metaverse(八)、RTC Engine 基于Agora声网SDK实现音视频通话

文章目录 简介创建应用构建应用场景API调用与回调事件测试 简介 本文介绍如何在Unity中接入声网SDK&#xff0c;它可以应用的场景有许多&#xff0c;例如直播、电商、游戏、社交等&#xff0c;音视频通话是其实时互动的基础能力。 如下图所示&#xff0c;可以在官网中选择Unit…

【Python实用基础整合(三)】儒略日计算、Pandas写Excel文件多Sheet以及datetime64[ns]时间格式处理

一、儒略日计算 儒略日&#xff08;Julian Day&#xff09;是在儒略周期内以连续的日数计算时间的计时法&#xff0c;主要用于天文学领域&#xff0c;SMOKE、CMAQ、CAMx等模型中也有使用。Linux中主要使用IOAPI库中的juldate和jul2greg来进行常规日期和儒略日的相互转化。Pyth…

MongoDB索引详解-03

MongoDB索引 索引是一种用来快速查询数据的数据结构。BTree 就是一种常用的数据库索引数据结构&#xff0c; MongoDB采用BTree 做索引 &#xff0c;索引创建在colletions上。MongoDB不使用索引的查 询&#xff0c;先扫描所有的文档&#xff0c;再匹配符合条件的文档。 使用索…

docker注意事项和https

docker容器安全注意&#xff1a; 尽量别做的事&#xff1a; 尽量不用 --privileged 运行容器授权容器root用户拥有宿主机的root权限 尽量不在 容器中运行 ssh 服务 尽量不用 --network host 使用 host 网络模式运行容器 尽量要做的事&#xff1a; 尽量使用最小化的镜像 尽量…

四六级套路总结

四六级 四级六级作文背多分 四级 英语四级&#xff08;必过12.10&#xff09; 听力&#xff1a; 全出现 头尾出现 &#xff08;直接选&#xff09; 长篇&#xff1a; 勾 8分钟&#xff0c;边勾边默念 念 勾完五句念一遍&#xff0c;十句通读&#xff08;时间够不要慌&#xff…

SpringSecurity从入门到精通

简介 ​ Spring Security 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架Shiro&#xff0c;它提供了更丰富的功能&#xff0c;社区资源也比Shiro丰富。 ​ 一般来说中大型的项目都是使用SpringSecurity 来做安全框架。小项目有Shiro的比较多&#xff0c;因为相比…

Three.js--》实现3D汽车展厅效果展示

目录 项目搭建 初始化three.js基础代码 加载汽车模型 设置展厅效果 设置GUI面板动态控制车身操作 车门操作与车身视角展示 设置手动点击打开关闭车门 设置图片背景 今天简单实现一个three.js的小Demo&#xff0c;加强自己对three知识的掌握与学习&#xff0c;只有在项目…

【振奋人心】中科院芯片突破,中国ai将逆袭

最近&#xff0c;中国科学院在人工智能芯片领域取得了一项重大突破。中科院计算技术研究所和中国电子科技集团公司第五十三研究所联合研发的新型神经网络加速器芯片&#xff0c;成功实现高效率和低功耗的特性&#xff0c;而且在典型人工智能测试中获取了高达1000倍计算效率的提…

滤波器设计总结

滤波器的主要参数 中心频率&#xff08;Center Frequency&#xff09;&#xff1a;滤波器通带的频率f0&#xff0c;一般取f0&#xff08;f1f2&#xff09;/2&#xff0c;f1、f2为带通或带阻滤波器左、右相对下降1dB或3dB边频点。窄带滤波器常以插损最小点为中心频率计算通带带…

开源大型语言模型(llm)总结

大型语言模型&#xff08;LLM&#xff09;是人工智能领域中的一个重要研究方向&#xff0c;在ChatGPT之后&#xff0c;它经历了快速的发展。这些发展主要涉及以下几个方面&#xff1a; 模型规模的增长&#xff1a;LLM的规模越来越大&#xff0c;参数数量显著增加。这种扩展使得…

11个Java开发者收藏的网站!

导读Java是一种面向对象的编程语言&#xff0c;由Sun Microsystems公司在1995年的时候正式发布。直到今天&#xff0c;Java都一直是最受欢迎的编程语言之一。如今&#xff0c;Java应用于各种各样的技术领域&#xff0c;例如网站开发、Android开发、游戏开发、大数据等等。 在世…

12-代码实战——服务器版表白墙

目录 1.版本一&#xff1a;将数据存到内存中 ①约定前后端交互接口 a.添加表白信息&#xff1a; b.查询表白列表&#xff1a; ②在webapp包下创建message-wall.html前端文件 ③在java包下创建AddMessageServlet后端类 ④在java包下创建MessageListServlet后端类 2.版本…