Redis学习(14)之Lua语法学习
创始人
2025-05-28 06:57:20
0

文章目录

  • 前言
  • 一 Lua基础语法
    • 1.1 注释
    • 1.2 数据类型
    • 1.3 标识符
      • 1.3.1 保留字
      • 1.3.2 变量
      • 1.3.3 动态类型
    • 1.3.3 运算符
      • 1.3.4 算术运算符
      • 1.3.5 关系运算符
      • 1.3.6 逻辑运算符
      • 1.3.7 其他运算符
    • 1.4 函数
      • 1.4.1 固定参函数
      • 1.4.2 可变参函数
      • 1.4.3 返回多个值
      • 1.4.4 函数作为参数
    • 1.5 流程控制语句
      • 1.5.1 if语句&if 嵌套语句
    • 1.6 循环控制语句
  • 二 Lua 语法进阶
    • 2.1 table
    • 2.2 table 操作函数
    • 2.3 迭代器
    • 2.4 模块
    • 2.5 元表与元方法
      • 2.5.1 重要函数和方法
    • 2.6 面向对象
    • 2.7 协同线程
    • 2.8 协同函数
    • 2.9 文件IO
      • 2.9.1 常用静态函数
      • 2.9.2 常用实例函数

前言

  • 学自动力节点,redis课程。本文仅供学习交流使用,禁止用于商业用途!!

一 Lua基础语法

1.1 注释

  • 行注释:--开头
  • 段注释:--[[开头,]]--结尾
  • 在调试过程中如果想临时取消段注释,而直接将其标识删除,这样做其实并不好。因为有可能还需要再添加上。而段注释的写法相对较麻烦。所以,Lua 给出了一种简单处理方式:在开头的–[[前再加一个减号,即可使段注释不起作用。其实就是使两个段注释标识变为了两个行注释。

1.2 数据类型

  • Lua 中有 8 种类型,分别为:nil、boolean、number、string、userdata、function、thread 和 table

  • 通过 type()函数可以查看一个数据的类型

  • nil:只有值 nil 属于该类,表示一个无效值,与 Java 中的 null 类似。但在条件表达式中相当于 false。

  • boolean :包含两个值:false 和 true。

  • number: 表示双精度类型的实浮点数。

  • string:字符串,由一对双引号或单引号括起来。当一个字符串包含多行时,可以在第一行中以[[开头,在最后一行中以]]结尾,那么在[[与]]括起来的这多行内容就是一个字符串。换行符为字符串”\n”。

  • table :类似于 Java 中的数组,但比数组的功能更强大,更灵活。

  • function :由 C 或 Lua 编写的函数。

  • thread:协同线程,是协同函数的执行体,即正在执行的协同函数。

  • userdata:一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据存储到 Lua 变量中调用

1.3 标识符

1.3.1 保留字

在这里插入图片描述

1.3.2 变量

  • Lua 是弱类型语言,变量无需类型声明即可直接使用。变量分为全局变量与局部变量。
  • Lua 中的变量默认都是全局变量,即使声明在语句块或函数里。全局变量一旦声明,在当前文件中的任何地方都可访问。局部变量 local 相当于 Java 中的 private 变量,只能在声明的语句块中使用。

1.3.3 动态类型

  • Lua 是动态类型语言,变量的类型可以随时改变,无需声明。

1.3.3 运算符

  • 运算符是一个特殊的符号,用于告诉解释器执行特定的数学或逻辑运算。
  • Lua 提供了以下几种运算符类型:
    • 算术运算符
    • 关系运算符
    • 逻辑运算符
    • 其他运算符

1.3.4 算术运算符

  • 设定 A 的值为 10,B 的值为 20
    在这里插入图片描述
  • SciTE 对 Lua 支持的目前最高版本为 5.1,而整除运算符//需要在 Lua5.3 版本以上,所以当前 SciTE 中无法看到效果。

1.3.5 关系运算符

  • 设定 A 的值为 10,B 的值为 20
    在这里插入图片描述

1.3.6 逻辑运算符

  • Lua 系统将 false 与 nil 作为假,将 true 与非 nil 作为真,即使是 0 也是真
  • 设定 A 的值为 true,B 的值为 false
    在这里插入图片描述

1.3.7 其他运算符

在这里插入图片描述

1.4 函数

  • Lua 中函数的定义是以 function 开头,后跟函数名与参数列表,以 end 结尾。 其可以没有返回值,也可以一次返回多个值。

1.4.1 固定参函数

  • Lua 中的函数在调用时,其不要求实参的个数必须与函数中形参的个数相同。如果实参个数少于形参个数,则系统自动使用 nil 填充;如果实参个数多于形参个数,多出的将被系统自动忽略。
-- 定义一个普通函数 包含两个形参
function f1(a,b)print(a,b)
end
print("无实参传递")
f1()
print("传递一个实参")
f1(666)
print("传递两个实参")
f1(666,888)
print("传递三个实参")
f1(666,888,999)

1.4.2 可变参函数

  • 在函数定义时不给出具体形参的个数,而是使用三个连续的点号。在函数调用时就可以向该函数传递任意个数的参数,函数可以全部接收。
-- 定义一个普通函数,包含可变参数
function f2(...)local a,b,c,d=...print(...)end
print("传递三个参数")
f2(10,20,30)
print("传递四个参数")
f2(10,20,30,40)
print("传递五个参数")
f2(10,20,30,40,50)

1.4.3 返回多个值

  • Lua 中的函数一次可以返回多个值,但需要有多个变量来同时接收。
-- 定义一个函数,返回两个值
function f3(a,b)local sum=a+blocal mul=a*breturn sum,mul;
end
-- 一次性接受两个值
m,n=f3(10,10)
print("一个函数返回多个值")
print(m,n)

1.4.4 函数作为参数

  • Lua 的函数中,允许函数作为参数。而作为参数的函数,可以是已经定义好的普通函数,也可以是匿名函数。
-- 定义两个普通函数
function sum(m,n)return m+n
end
function mul(m,n)return m*n
end
function complex(m,n,fun)local result=fun(m,n)print(result)
end
-- 普通调用
complex(3,4,sum)
complex(3,4,mul)
-- 匿名函数调用
complex(3,4,function(a,b)return a-b;end
);

1.5 流程控制语句

1.5.1 if语句&if 嵌套语句

  • Lua 提供了 if…then 用于表示条件判断,其中 if 的判断条件可以是任意表达式。
  • Lua 中的 if 语句的判断条件可以使用小括号括起来,也可以不使用
a=10
if a>9 thenprint("num>0")
elseif num==0 thenprint("num = 0")
elseprint("num<0")
end
  • Lua 中提供了专门的关键字 elseif 来做 if 嵌套语句。注意,不能使用 elseif 两个关键字的联用形式,即不能使用 else if 来嵌套 if 语句
a=10
if a>9 thenprint("num>0")
elseif num==0 thenprint("num = 0")
elseprint("num<0")
end

1.6 循环控制语句

  • Lua 提供了四种循环控制语句:while…do 循环、repeat…until 循环、数值 for 循环,及泛型 for 循环。
  • 同时,Lua 还提供了 break 与 goto 两种循环流程控制语句。
  1. while...do

    • 只要 while 中的条件成立就一直循环。
    score=450
    while score>= 425 doprint("过了")score=score-1
    end
    
  2. repeat...until

    • until 中的条件成立了,循环就要停止。
    score=450
    repeatprint(score)score=score+1
    until score>=427
    
  3. 数值 for

    • 这种 for 循环只参用于循环变量为数值型的情况。其语法格式为:
    for var=exp1, exp2, exp3 do--循环体
    end
    
    for i=10,60,10 doprint(i)
    end
    
    • var 为指定的循环变量,exp1 为循环起始值,exp2 为循环结束值,exp3 为循环步长。步长可省略不写,默认为 1。每循环一次,系统内部都会做一次当前循环变量 var 的值与 exp2的比较,如果 var 小于等于 exp2 的值,则继续循环,否则结束循环。
  4. 泛型 for

    • 泛型 for 用于遍历 table 中的所有值,其需要与 Lua 的迭代器联合使用。
    -- 遍历emp中所有数组元素
    for k,v in ipairs(emp) doprint(k,v)
    end
    
  5. break

    • break 语句可以提前终止循环。其只能用于循环之中
  6. goto

    • goto 语句可以将执行流程无条件地跳转到指定的标记语句处开始执行。当然,该标识语句在第一次经过时也是会执行的,并非是必须由 goto 跳转时才执行。
    • 语句标记使用一对双冒号括起来,置于语句前面。goto 语句可以使用在循环之外。
  • Lua5.1 中不支持双冒号的语句标记。

二 Lua 语法进阶

2.1 table

  1. 数组
    • 使用 table 可以定义一维、二维、多维数组。
    • Lua 中的数组索引是从 1开始的,且无需声明数组长度,可以随时增加元素。同一数组中的元素可以是任意类型。
    -- 声明一个空的数组
    arr={}
    for i=1,3 do-- 声明空数组arr[i]={}for j=1,3 doarr[i][j]=i*jend
    end
    for i=1,3 dofor j=1,3 doprint(arr[i][j])end
    end
    
  2. map
    • 使用 table 也可以定义出类似 map 的 key-value 数据结构。其可以定义 table 时直接指定key-value,也可单独指定 key-value。而访问时,一般都是通过 table 的 key 直接访问,也可以数组索引方式来访问,此时的 key 即为索引。
    -- 定义一个map
    emp={name="张三",age=23,depart="销售"}
    -- 通过下标方式操作
    emp["gender"]="男"
    print(emp["name"])
    print(emp["gender"])
    emp.workAge=3
    print(emp.workAge)
    print(emp.name)
    
  3. 混合结构
    • Lua 允许将数组与 key-value 混合在同一个 table 中进行定义。
    • key-value 不会占用数组的数字索引值。
    -- 定义一个数组,map混合结构
    emps={{name="001",age=11},{name="002",age=12},{name="003",age=13},{name="004",age=14}
    }
    for i=1,4 doprint(emps[i].name..":"..emps[i].age)
    end
    

2.2 table 操作函数

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

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

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

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

  • table.maxn()
    table.maxn(table)
    
    • 该函数返回指定 table 的数组中的最大索引值,即数组包含元素的个数。

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

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

  • table.sort()
    table.sort(table [,fun(a,b)])
    
    • 该函数用于对指定的 table 的数组元素进行升序排序,也可按照指定函数 fun(a,b)中指定的规则进行排序。fun(a,b)是一个用于比较 a 与 b 的函数,a 与 b 分别代表数组中的两个相邻元素。
    • 如果 arr 中的元素既有字符串又有数值型,那么对其进行排序会报错。
    • 如果数组中多个元素相同,则其相同的多个元素的排序结果不确定,即这些元素的索引顺序不确定。
    • 如果数组元素中包含 nil,则排序会报错。

2.3 迭代器

  • Lua 提供了两个迭代器 pairs(table)ipairs(table)。这两个迭代器通常会应用于泛型 for循环中,用于遍历指定的 table。这两个迭代器的不同是:
    • ipairs(table):仅会迭代指定 table 中的数组元素。
    • pairs(table):会迭代整个 table 元素,无论是数组元素,还是 key-value。
emp={"apple",type="fruit",health="true",yieldly="east","banana","tangerine","grape"}
print(table.concat(emp,",",2))
print(table.concat(emp,",",2,3))
-- 遍历emp中所有数组元素
for k,v in ipairs(emp) doprint(k,v)
end
-- 遍历emp中所有的元素
for k,v in pairs(emp) doprint(k,v)
end

2.4 模块

  • 模块是Lua中特有的一种数据结构。从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度。
  • 模块文件主要由 table 组成。在 table 中添加相应的变量、函数,最后文件返回该 table即可。如果其它文件中需要使用该模块,只需通过 require 将该模块导入即可。
  1. 定义一个模块
    • 模块是一个 lua 文件,其中会包含一个 table。一般情况下该文件名与该 table 名称相同,但其并不是必须的。
    • 定义模块rectangle.lua
    -- 声明一个模块
    rectangle={}--为模块添加一个变量
    rectangle.pi = 3.14--为模块添加函数(求周长)
    function rectangle.perimeter(a, b)return (a+b)* 2
    end--以匿名函数方式为模块添加一个函数(求面积)
    rectangle.area = function(a,b)return a*b
    end--定义与模块无关的内容-- 定义一个全局变量
    goldenRatio=0.618--定义一个局部函数(求圆的面积)
    local function circularArea(r)return rectangle.pi*r*r
    end--定义一个全局函数(求矩形中最大圆的面积)
    function maxcircularArea(a,b)local r=math.min(a,b)return circularArea(r)
    endreturn rectangle
    
  2. 使用模块
    • 用函数 require(“文件路径”),【文件名是不能写.lua 扩展名】该函数可以将指定的 lua 文件静态导入(合并为一个文件)。
    • 注意:该函数的使用可以省略小括号,写为 require “文件路径”。
    • require()函数是有返回值的,返回的就是模块文件最后 return 的 table。可以使用一个变量接收该 table 值作为模块的别名,就可以使用别名来访问模块了。
    -- 导入模块
    rect=require "rectangle"
    -- 访问模块的属性,调用模块的函数
    print(rectangle.pi)
    print(rectangle.perimeter(3,5))
    print(rectangle.area(3,5))print(rect.perimeter(3,5))
    print(rect.area(3,5))
    
  3. 再看模块
    • 模块文件中一般定义的变量与函数都是模块 table 相关内容,但也可以定义其它与 table无关的内容。这些全局变量与函数就是普通的全局变量与函数,与模块无关,但会随着模块的导入而同时导入。所以在使用时可以直接使用,而无需也不能添加模块名称。
    -- 访问模块中与模块无关的内容
    print(goldenRatio)
    print(maxcircularArea(3,5))
    

2.5 元表与元方法

  • 元数据:描述数据的数据(如:数据库名、表名、字段名)
  • 元数据表:描述表的另外的表(如:表A由表B描述)
  • 元表,即 Lua 中普通 table 的元数据表,而元方法则是元表中定义的普通表的默认行为。 Lua 中的每个普通 table 都可为其定义一个元表,用于扩展该普通 table 的行为功能。
  • 例如,对于 table 与数值相加的行为,Lua 中是没有定义的,但用户可通过为其指定元表来扩展这种行为;再如,用户访问不存在的 table 元素,Lua 默认返回的是 nil,但用户可能并不知道发生了什么。此时可以通过为该 table 指定元表来扩展该行为:给用户提示信息,并返回用户指定的值

2.5.1 重要函数和方法

  • 元表中有两个重要函数:
    • setmetatable(table,metatable):将 metatable 指定为普通表 table 的元表。
    • getmetatable(table):获取指定普通表 table 的元表。
  1. _ _index 元方法
    • 当用户在对 table 进行读取访问时,如果访问的数组索引或 key 不存在,那么系统就会自动调用元表的_ _index 元方法。该重写的方法可以是一个函数,也可以是另一个表。如果重写的_ _index 元方法是函数,且有返回值,则直接返回;如果没有返回值,则返回 nil
    -- 以函数方式重写__index方法
    emp={"apple",type="fruit",health="true",yieldly="east","banana","tangerine","grape"}
    print(emp.x) --nil--声明一个元表
    meta ={};
    --将原始表与元表相关联
    setmetatable(emp , meta)--有返回值的情况
    meta._index = function(tab,key)return (key.."值不存在")
    end--无返回值的情况
    meta.__index =function(tab, key)print("通过["..key.."]访问的值不存在")
    endprint(emp.x) --nil
    print(emp[2]) --banana
    
    emp2={"apple",type="fruit",health="true",yieldly="east","banana","tangerine","grape"}
    print(emp2[5]) --nil
    --声明一个元表
    meta2={}
    --将原始表与元表相关联
    setmetatable(emp2,meta2)--再定义一个普通表
    others={}
    others[5]="strawberry"
    others[6]="ananas"-- 指定元表为另一个普通表
    meta2.__index=others--在原始表中若找不到,则会到元表指定的普通表中查找
    print(emp2[5]) --strawberry
    
  2. _ _newindex 元方法
    • 当用户为 table 中一个不存在的索引或 key 赋值时,就会自动调用元表的_ _newindex 元方法。该重写的方法可以是一个函数,也可以是另一个表。如果重写的_ _newindex 元方法是函数,且有返回值,则直接返回;如果没有返回值,则返回 nil
    emp3={"apple",type="fruit",health="true",yieldly="east","banana","tangerine","grape"}
    print(emp3[5]) --nil
    --声明一个元表
    meta3={}
    --将原始表与元表相关联
    setmetatable(emp3,meta3)
    -- 无返回值的情况
    function meta3.__newindex(tab,key,value)print(key..":"..value)-- 将新增的key-value写入到原始表rawset(tab,key,value)
    endemp3.x="ming"
    print(emp3.x) -- ming
    
    emp4={"apple",type="fruit",health="true",yieldly="east","banana","tangerine","grape"}
    print(emp4[5]) --nil--声明一个元表
    meta4={}
    --将原始表与元表相关联
    setmetatable(emp4,meta4)
    -- 定义一个普通表
    other4={}
    -- 元表指定额另一个普通表的作用是,暂存新增的数据
    meta4.__newindex=other4
    emp4.x="ming"
    print(emp4.x) --nil
    print(other4.x) --ming
  3. 运算符元方法
    • 如果要为一个表扩展加号(+)、减号(-)、等于(==)、小于(<)等运算功能,则可重写相应的元方法。
    • 例如,如果要为一个 table 扩展加号(+)运算功能,则可重写该 table 元表的_ _add 元方法,而具体的运算规则,则是定义在该重写的元方法中的。这样,当一个 table 在进行加法(+)运算时,就会自动调用其元表的_ _add 元方法
    -- 运算符元方法
    emp5={"apple",type="fruit",health="true",yieldly="east","banana","tangerine","grape"}
    -- 声明一个元表
    meta5={__add=function(tab,num)-- 遍历tab中的所有元素for k,v in pairs(tab) do--若value为数值类型,做算数运算if type(v)=="number" thentab[k]=v+num--若value为string,做字符拼接elseif type(v)=="string" thentab[k]=v..numendend-- 返回变化后的tablereturn tabend
    };--将原始表与元表相关联
    setmetatable(emp5,meta5)
    emp5=emp5+5for k,v in pairs(emp5) doprint(k.."  :  "..v)
    end
    
  • 其它操作
元方法说明
__add加法,+
__sub减法,-
__mul乘法,*
__div除法,/
__mod取模,%
__pow次幂,^
__unm取反,-
__idiv取整除法,//
__lt小于,<
__concat字符串连接,…
__len字符串长度,#
__band按位与,&
__bor按位或,
__bxor按位异或,~
__bnot按位非,~
__shl按位左移,<<
__shr按位右移,>>
__eq等于,==
__le小于等于,<=
  1. _ _tostring 元方法
    • 直接输出一个 table,其输出的内容为类型与 table 的存放地址。如果想让其输出 table中的内容,可重写_ _tostring 元方法
    -- __tostring方法
    emp6={"apple",type="fruit",health=1,yieldly="east","banana","tangerine","grape"}
    -- 声明一个元表
    meta6={__add=function(tab,num)-- 遍历tab中的所有元素for k,v in pairs(tab) do--若value为数值类型,做算数运算if type(v)=="number" thentab[k]=v+num--若value为string,做字符拼接elseif type(v)=="string" thentab[k]=v..numendend-- 返回变化后的tablereturn tabend, -- 这里需要加上一个逗号__tostring=function(tab)str=""--字符串拼接for k,v in pairs(emp6) dostr=str.." "..k..":"..vendreturn strend
    };-- 将原始表与元表相关联
    setmetatable(emp6,meta6)emp6=emp6+10
    print(emp6)
    
  2. _ _call 元方法
    • 当将一个 table 以函数形式来使用时,系统会自动调用重写的_ _call 元方法。该用法主要是可以简化对 table 的相关操作,将对 table 的操作与函数直接相结合。
    -- __call方法
    emp7={"apple",type="fruit",health=1,yieldly="east","banana","tangerine","grape"}
    -- 将原始表与元表相关联 匿名函数
    setmetatable(emp7,{__call=function(tab,num,str)-- 遍历tablefor k,v in pairs(tab) do--若value为数值类型,做算数运算if type(v)=="number" thentab[k]=v+num--若value为string,做字符拼接elseif type(v)=="string" thentab[k]=v..numendendreturn tabend
    })newemp=emp7(5,"-hello")
    for k,v in pairs(newemp) doprint(k..":"..v)
    end
    
  3. 元表单独定义
    • 为了便于管理与复用,可以将元表单独定义为一个文件。该文件中仅可定义一个元表,且一般文件名与元表名称相同。
    • 若一个文件要使用其它文件中定义的元表,只需使用 require “元表文件名”即可将元表导入使用。
    • 如果用户想扩展该元表而又不想修改元表文件,则可在用户自己文件中重写其相应功能的元方法即可。

2.6 面向对象

  1. 简单对象的创建

    • Lua 中通过 table 与 fcuntion 可以创建出一个简单的 Lua 对象:table 为 Lua 对象赋予属性,通过 function 为 Lua 对象赋予行为,即方法
    -- 简单对象的创建
    -- 创建一个animal对象
    animal={name="Tom",age=3,
    say=function(voice)print(animal.name.."正在"..voice.."叫")
    end}
    -- 添加方法
    animal.run=function(speed)print(animal.name.."正在以"..speed.."m/s前进")
    end
    animal.say("喵喵")
    animal.run(5)
    -- 创建对象的指针,观察是否指向同一个对象
    animal2=animal
    -- 打印对象的名字和地址
    print(animal2.name, animal2)
    print(animal.name, animal)-- self代表当前的实例
    -- 冒号中会自动包含一个self参数,相当于this
    function animal:play(games)print(self.name.."正在玩"..games.."游戏")
    end
    -- 将animal置空
    animal=nil
    animal2.name="philips"
    animal2:play("捉迷藏")
  2. 类的创建

    • Lua 中使用 table、function 与元表可以定义出类:使用一个表作为基础类,使用一个function 作为该基础类的 new()方法。在该 new()方法中创建一个空表,再为该空表指定一个元表。该元表重写_ _index 元方法,且将基础表指定为重写的_ _index元方法。由于 new()中的表是空表,所以用户访问的所有 key 都会从基础类(表)中查找。
    -- 创建类
    Animal={name="no_name",age=1}
    function Animal:bark(voice)print(self.name..voice.."叫")
    end
    -- 为该类添加一个无参构造器
    function Animal:new()-- 创建一个空表local a={}-- 为新表指定元素为当前基类表-- 如果后续操作,没有在a表中找到相关的数据,就从Animal表中查找,如果Animal中也没有就返回空setmetatable(a,{__index=self})-- 返回新表return a
    endanimal01=Animal:new()
    animal02=Animal:new()
    print(animal01)
    print(animal02)-- 给表a属性赋值
    animal01.name="TOM"
    animal01.age=3
    animal01.type="猫"
    --
    print(animal01.name.."是一只"..animal01.age.."岁的"..animal01.type)function animal02:skill()return "我会捉老鼠"
    end
    print(animal02.name..animal02.age.."岁,"..animal02.skill())
    
    -- 类的继承
    BaseAnimal={name="no_name",age=1}
    function BaseAnimal:bark(voice)print(self.name..voice.."叫")
    end
    -- 为该类添加一个无参构造器
    function BaseAnimal:new()-- 创建一个空表local a={}-- 为新表指定元素为当前基类表-- 如果后续操作,没有在a表中找到相关的数据,就从Animal表中查找,--如果Animal中也没有就返回空setmetatable(a,{__index=self})-- 返回新表return a
    end-- 为该类添加一个带参构造器
    function BaseAnimal:new(obj)local a=obj or {}setmetatable(a,{__index=self})-- 返回新表return a
    endanimal03=BaseAnimal:new()
    -- 调用带参构造器 实参为一个匿名表
    animal04=BaseAnimal:new({type="猫"})animal04.name="jerry"
    animal04.age=3
    print(animal04.name.." : "..animal04.age.."岁,"..animal04.type)--为Animal类创建一个子类cat
    cat = BaseAnimal:new({type="波斯猫"})
    cat.eyes ="蓝眼睛"tomcat = cat : new()
    tomcat.name = "Tom"print(tomcat.name.."是"..tomcat.eyes.."的"..tomcat.type)

2.7 协同线程

  • Lua 中有一种特殊的线程,称为 coroutine,协同线程,简称协程。其可以在运行时暂停执行,然后转去执行其它线程,然后还可返回再继续执行没有执行完毕的内容。即可以“走走停停,停停再走走”。
  • 协同线程也称为协作多线程,在 Lua 中表示独立的执行线程。任意时刻只会有一个协程执行,而不会出现多个协程同时执行的情况。
  • 协同线程的类型为 thread,其启动、暂停、重启等,都需要通过函数来控制。
  • 用于控制协同线程的基本方法。
    在这里插入图片描述
    -- 协同线程
    -- 创建一个协同线程实例
    crt=coroutine.create(function(a,b)print(a,b,a+b)-- 获取正在运行的协同线程的实例,thread类型tr=coroutine.running();print(tr)-- 查看协同线程实例的类型print(type(tr))-- 查看系统线程实例的状态print(coroutine.status(crt))-- 将当前协同线程实例挂起coroutine.yield()print("线程又重新返回到了协同线程")end
    )-- 启动协同线程实例
    coroutine.resume(crt,3,5)-- 查看crt类型
    print("main-"..type(crt))-- 查看协同线程实例的状态
    print("main-"..coroutine.status(crt))--继续执行协同线程
    coroutine .resume (crt, 3,5)--查看协同线程实例的状态
    print ( "main-"..coroutine.status (crt))
    
    -- 创建一个协同线程实例
    crt2=coroutine.create(function(a,b)print(a,b)-- 将当前线程挂起,同时携带两个返回值coroutine.yield(a*b,a/b)print("线程又重新返回到了协同线程")-- 返回两个值return a+b,a-bend
    )
    --启动协同线程,返回三个值
    --第一个返回值为协同线程启动成功状态
    --后面的返回值为内置函数的返回值
    success1, resu1t1,result2 = coroutine.resume(crt2,12,3)print(success1,resu1t1,result2)success2,result1,result2 = coroutine.resume(crt2)
    print(success2,result1,result2)

2.8 协同函数

  • 协同线程可以单独创建执行,也可以通过协同函数的调用启动执行。使用 coroutine 的wrap()函数创建的就是协同函数,其类型为 function。
  • 由于协同函数的本质就是函数,所以协同函数的调用方式就是标准的函数调用方式。只不过,协同函数的调用会启动其内置的协同线程。
    -- 协同函数--创建一个协同函数
    cf =coroutine.wrap(function(a,b)print(a,b)-- 获取当前协同函数创建的协同线程tr=coroutine.running()print("tr的类型为:"..type(tr))-- 挂起当前的协同线程-- 也可以添加返回的参数,如返回协同线程的实例-- coroutine.yield(coroutine.running(),a+1,b+1)coroutine.yield(a+1,b+1)print("线程又重新返回到了协同线程")return a+b,a*bend
    )
    -- 调用协同函数,启动协同线程
    result1,result2=cf(3,5)
    print(result1,result2)print("cf的类型为:"..type(cf))-- 重启挂起的协同线程result1,result2=cf(3,5)
    print(result1,result2)--[[
    -- 调用协同函数,启动协同线程
    cftr,result1,result2=cf(3,5)
    -- 重启挂起的协同线程
    success,result1,result2=coroutine.resume(cftr)]]--
    

2.9 文件IO

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

2.9.1 常用静态函数

  1. io.open()
    io.open (filename [, mode])
    
    • 以指定模式打开指定文件,返回要打开文件的句柄,就是一个对象。
    • 其中模式 mode 有三种,但同时还可配合两个符号使用:
      • r:只读,默认模式
      • w:只写,写入内容会覆盖文件原有内容
      • a:只写,以追加方式写入内容
      • +:增加符,在 r+、w+、a+均变为了读写
      • b:二进制表示符。如果要操作的文件为二进制文件,则需要变为 rb、wb、ab。
  2. io.input()
    io.input (file)
    
    • 指定要读取的文件。
  3. io.output()
    io.output (file)
    
    • 指定要写入的文件。
  4. io.read()
    io.read([format])
    
    • 以指定格式读取 io.input()中指定的输入文件。其中 format 格式有:
      • *l:从当前位置的下一个位置开始读取整个行,默认格式
      • *n:读取下一个数字,其将作为浮点数或整数
      • *a:从当前位置的下一个位置开始读取整个文件
      • number:这是一个数字,表示要读取的字符的个数
  5. io.write()
    io.write(data)
    
    • 将指定的数据 data 写入到 io.output()中指定的输出文件。

2.9.2 常用实例函数

  1. file:read()
    • 这里的 file 使用的是 io.open()函数返回的 file,其实际就是 Lua 中的一个对象。其用法与 io.read()的相同。
  2. file:write()
    • 用法与 io.write()的相同。
  3. file:seek()
    file:seek ([whence [, offset]])
    
    • 该函数用于获取或设置文件读写指针的当前位置。位置从 1 开始计数,除文件最后一行外,每行都有行结束符,其会占两个字符位置。位置 0 表示文件第一个位置的前面位置。
    • 当 seek()为无参时会返回读写指针的当前位置。参数 whence 的值有三种,表示将指针定位的不同位置。而 offset 则表示相对于 whence 指定位置的偏移量,offset 的默认值为 0,为正表示向后偏移,为负表示向前偏移。
      • set:表示将指针定位到文件开头处,即 0 位置处
      • cur:表示指针保持当前位置不变,默认值
      • end:表示将指针定位到文件结尾处

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...