Lua
Lua笔记
lua5.3参考手册: luatos.com
简介
描述
Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放; 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
特性
- 轻量级
- 可扩展
- 其它特性:支持面向过程、自动内存管理、语言内置模式匹配、支持面向对象
应用场景
- 游戏开发
- 独立应用脚本
- Web 应用脚本
- 扩展和数据库插件如:MySQL Proxy 和 MySQL WorkBench
- 安全系统,如入侵检测系统
Linux环境安装
curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gztar zxf lua-5.3.0.tar.gzcd lua-5.3.0make linux testmake installMacOS环境安装
curl -R -O http://www.lua.org/ftp/lua-5.3.0.tar.gztar zxf lua-5.3.0.tar.gzcd lua-5.3.0make macosx testmake installWindow环境安装
- Github下载安装包
- Github 下载地址 : https://github.com/rjpcomputing/luaforwindows/releases
- Google Code下载地址 : https://code.google.com/p/luaforwindows/downloads/list
- 双击安装后即可在该环境下编写 Lua 程序并运行
基础语法
语法
lua代码程序后缀 .lua
打印
print("hello")注释
-- 单行注释
--[[ 多行注释 多行注释 --]]变量命名
Lua 标示符用于定义一个变量,函数获取其他用户定义的项。 标示符以一个字母 A 到 Z 或 a 到 z 或下划线 _ 开头后加上 0 个或多个字母,下划线,数字(0 到 9)。 不要使用下划线加大写字母的标示符,因为Lua的保留字也是这样的。 Lua 不允许使用特殊字符如 @, $, 和 % 来定义标示符。 Lua 是一个区分大小写的编程语言。 在默认情况下,变量总是认为是全局的。 PS:如果你想删除一个全局变量,只需要将变量赋值为nil。
关键词
一般约定,以下划线开头连接一串大写字母的名字(比如_VERSION)被保留用于 Lua 内部全局变量。
| and | break | do | else |
|---|---|---|---|
| elseif | end | false | for |
| function | if | in | local |
| nil | not | or | repeat |
| return | then | true | until |
| while | goto |
作用域
- 全局变量
- Lua 中的变量默认全局变量,无论语句块或是函数里
- 变量默认值均为nil
- 局部变量
- 用 local 显式声明为局部变量,局部变量只在被声明的那个代码块内有效
- 变量默认值均为nil
- 代码块:指的是一个控制结构内,一个函数体,或者一个chunk(变量被声明的那个文件或者文本串)
- 局部变量的作用域为从声明位置开始到所在语句块结束
- 表中域
尽可能使用局部变量,有两个好处
- 避免命名冲突
- 访问局部变量的速度比全局变量更快
- 原因是local变量是存放在lua的堆栈里面的是array操作,而全局变量是存放在_G中的table中,效率不及堆栈
数据类型
Lua 中有 8 个基本类型分别为:nil、boolean、number、string、userdata、function、thread 和 table。
| 数据类型 | 描述 |
|---|---|
| nil | 只有值nil属于该类,表示一个无效值(在条件表达式中相当于false)。 |
| boolean | 包含两个值:false和true。 |
| number | 表示双精度类型的实浮点数 |
| string | 字符串由一对双引号或单引号来表示 |
| function | 由 C 或 Lua 编写的函数 |
| userdata | 表示任意存储在变量中的C数据结构 |
| thread | 表示执行的独立线路,用于执行协同程序 |
| table | Lua 中的表(table)其实是一个”关联数组”(associative arrays),数组的索引可以是数字、字符串或表类型。在 Lua 里,table 的创建是通过”构造表达式”来完成,最简单构造表达式是{},用来创建一个空表。 |
实例
print(type("Hello world")) --> stringprint(type(10.4*3)) --> numberprint(type(print)) --> functionprint(type(type)) --> functionprint(type(true)) --> booleanprint(type(nil)) --> nilprint(type(type(X))) --> string基本变量
nil
nil 作比较时应该加上双引号 ”: type(X) 实质是返回的 “nil” 字符串,是一个 string 类型
> type(X)nil> type(X)==nilfalse> type(X)=="nil"true>对于全局变量和 table,nil 还有一个”删除”作用,给全局变量或者 table 表里的变量赋一个 nil 值,等同于把它们删掉
tab1 = { key1 = "val1", key2 = "val2", "val3" }for k, v in pairs(tab1) do print(k .. " - " .. v)end
tab1.key1 = nilfor k, v in pairs(tab1) do print(k .. " - " .. v)endnumber
Lua 把 false 和 nil 看作是 false,其他的都为 true,数字 0 也是 true
Lua 默认只有一种 number 类型 — double(双精度)类型(默认类型可以修改 luaconf.h 里的定义)
print(type(2))print(type(2.2))print(type(0.2))print(type(2e+1))print(type(0.2e-1))print(type(7.8263692594256e-06))-- 字符串转numberprint(tonumber("3333")) -- 3333print(tonumber("aaa")) -- nil大小端
对于一个由2个字节组成的16位整数,在内存中存储这两个字节有两种方法:
- 小端(little-endian)字节序: 低序字节存储在起始地址
- 大端(big-endian)字节序: 高序字节存储在起始地址。又称为网络序
uint32_t n = 0x01020304
# 大端顺序0x01, 0x02, 0x03, 0x04# 小端顺序0x04, 0x03, 0x02, 0x01不同CPU型号大小端模式不同, 判断大小端方式
#include <stdio.h>
// 共用体中很重要的一点:a和b都是从u1的低地址开始存放的。// 假设u1所在的4字节地址分别是:0、1、2、3的话,那么a自然就是0、1、2、3;// b所在的地址是0而不是3.
union myunion{ int a; char b;};
// 如果是小端模式则返回1,小端模式则返回0int is_little_endian(void){ union myunion u1; u1.a = 0x12345678; // 地址0的那个字节内是0x78(小端)或者0x12(大端) if(0x78 == u1.b) return 1; else if(0x12 == u1.b) return 0;}
int is_little_endian2(void){ int a = 0x12345678; char b = *((char *)(&a)); // 指针方式其实就是共用体的本质 if(0x78 == b) return 1; else if(0x12 == b) return 0;}
int main(void){ int i = is_little_endian2(); //int i = is_little_endian(); if (i == 1) { printf("小端模式\n"); } else { printf("大端模式\n"); }
return 0;}Lua中对二进制数据打包、解析
local data = string.pack("<L", 0x01020304)print(data:byte(1)) -- 4print(data:byte(2)) -- 3print(data:byte(3)) -- 2print(data:byte(4)) -- 1local str = string.unpack("<L", data)print(str) -- 16909060字符串
字符串由一对双引号或单引号来表示,也可以用 2 个方括号 ”[[]]” 来表示”一块”字符串 lua中字符串可以存储任何Byte值 字符串下标从1开始,反序下标从-1开始
string1 = "this is string1"string2 = 'this is string2'html = [[<html><head></head><body> <a href="http://www.runoob.com/">菜鸟教程</a></body></html>]]print(html)
print(str:byte(15)) -- 49print(str:byte(-1)) -- 49在对一个数字字符串上进行算术操作时,Lua 会尝试将这个数字字符串转成一个数字
> print("2" + 6)8.0> print("2" + "6")8.0字符串连接使用 ..
> print("a" .. 'b')ab> print(157 .. 428)157428>使用 # 来计算字符串的长度,放在字符串前面
> len = "www.runoob.com"> print(#len)14> print(#"www.runoob.com")14>语法糖
local str = "123"print(string.byte(str, 1)) -- 49print(str:byte(1)) -- 49内建函数
| 序号 | 方法 & 用途 |
|---|---|
| string.upper | string.upper(argument) : 字符串全部转为大写字母。 |
| string.lower | string.lower(argument): 字符串全部转为小写字母。 |
| string.gsub | **string.gsub(mainString,findString,replaceString,num)**在字符串中替换。mainString 为要操作的字符串, findString 为被替换的字符,replaceString 要替换的字符,num 替换次数(可以忽略,则全部替换),如:> string.gsub("aaaa","a","z",3); zzza 3 |
| string.find | string.find (str, substr, [init, [plain]]) 在一个指定的目标字符串 str 中搜索指定的内容 substr,如果找到了一个匹配的子串,就会返回这个子串的起始索引和结束索引,不存在则返回 nil。init 指定了搜索的起始位置,默认为 1,可以一个负数,表示从后往前数的字符个数。plain 表示是否使用简单模式,默认为 false,true 只做简单的查找子串的操作,false 表示使用使用正则模式匹配。以下实例查找字符串 “Lua” 的起始索引和结束索引位置:> string.find("Hello Lua user", "Lua", 1) 7 9 |
| string.reverse | string.reverse(arg) 字符串反转> string.reverse("Lua") auL |
| string.forma | string.format(…) 返回一个类似printf的格式化字符串> string.format("the value is:%d",4) the value is:4 |
| string.char/string.byte | string.char(arg) 和 string.byte(arg[,int]) char 将整型数字转成字符并连接, byte 转换字符为整数值(可以指定某个字符,默认第一个字符)。> string.char(97,98,99,100) abcd > string.byte("ABCD",4) 68 > string.byte("ABCD") 65 > |
| string.len | string.len(arg) 计算字符串长度。string.len("abc") 3 |
| string.rep | string.rep(string, n) 返回字符串string的n个拷贝> string.rep("abcd",2) abcdabcd |
| string.gmatch | string.gmatch(str, pattern) 返回一个迭代器函数,每一次调用这个函数,返回一个在字符串 str 找到的下一个符合 pattern 描述的子串。如果参数 pattern 描述的字符串没有找到,迭代函数返回nil。> for word in string.gmatch("Hello Lua user", "%a+") do print(word) end Hello Lua user |
| string.match | string.match(str, pattern, init) string.match()只寻找源字串str中的第一个配对. 参数init可选, 指定搜寻过程的起点, 默认为1。 在成功配对时, 函数将返回配对表达式中的所有捕获结果; 如果没有设置捕获标记, 则返回整个配对字符串. 当没有成功的配对时, 返回nil。> = string.match("I have 2 questions for you.", "%d+ %a+") 2 questions > = string.format("%d, %q", string.match("I have 2 questions for you.", "(%d+) (%a+)")) 2, "questions" |
| string.sub | string.sub(): 用于截取字符串string.sub(s, i [, j])。s:要截取的字符串;i:截取开始位置;j:截取结束位置,默认为 -1,最后一个字符。 |
table
table 的创建是通过”构造表达式”来完成,最简单构造表达式是{},用来创建一个空表;也可以在表里添加任意数据,直接初始化表
-- 创建一个空的 tablelocal tbl1 = {}
-- 直接初始表local tbl2 = {"apple", "pear", "orange", "grape"}
-- 构造键值对local tbl3 = {a=11, b="3", c=function() print("123") end, [",;"]=123 }local tbl4 = {[1]=1,2,3,[4]=4,5}对 table 的索引使用方括号 []。Lua 也提供了 . 操作。
t[i]t.i -- 当索引为字符串类型时的一种简化写法gettable_event(t,i) -- 采用索引访问本质上是一个类似这样的函数调用table实质为”关联数组”(associative arrays),数组的索引可以是数字或者是字符串。
a = {}a["key"] = "value"key = 10a[key] = 22a[key] = a[key] + 11for k, v in pairs(a) do print(k .. " : " .. v)end
--[[key : value10 : 33]]table默认初始索引一般以 1 开始,没有固定长度大小,随数据集新增而自动增长,未初始的数据返回nil ```lua tb = {1,2,3,4} print(tb[0]) — nil print(tb[1]) — 1 tb[0] = “11” print(tb[0]) — 11 print(tb[4]) — nil
全局变量统一存储在全局表(`_G`)中```Luatb = {1,2,3,4}print(_G) -- table: 0x24ffb80print(_G.tb[1]) -- 1print(_G.table.insert) -- function: 0x41d420迭代器:pairs/ipairs
- pairs: 用于迭代table所有数据 返回下标以及值
- ipairs:用于返回int类型下标的数据,遇到不连续的下标时终止循环
- 内部同步next(table,index)函数实现
local t = {[0]="a", [4]=4, 5, [6]="b"}for index,value in pairs(t) do print(index,value) end--[[1 50 a6 b4 4]]
local t = {[1]="a", [2]="b", [3]="c",[4]="d", [6]="e"}for i,j in ipairs(t) do print(i, j) end--[[1 a2 b3 c4 d]]
local t = {[1]="a", [2]="b", [3]="c",[4]="d", [6]="e"}print(next(t)) -- 1 aprint(next(t,4)) -- 6 eprint(next(t,6)) -- nilprint(next({})) -- nilfunction
Lua 编程语言函数定义格式如下:
optional_function_scope function function_name( argument1, argument2, argument3..., argumentn) function_body return result_params_comma_separatedend- optional_function_scope: 该参数是可选的指定函数是全局函数还是局部函数,未设置该参数默认为全局函数,如果你需要设置函数为局部函数需要使用关键字 local。
- function_name: 指定函数名称。
- argument1, argument2, argument3…, argumentn: 函数参数,多个参数以逗号隔开,函数也可以不带参数。
- function_body: 函数体,函数中需要执行的代码语句块。
- result_params_comma_separated: 函数返回值,Lua语言函数可以返回多个值,每个值以逗号隔开。
在 Lua 中,函数是被看作是”第一类值(First-Class Value)“,函数可以存在变量里
function factorial1(n) if n == 0 then return 1 else return n * factorial1(n - 1) endendprint(factorial1(5))factorial2 = factorial1print(factorial2(5))
--[[120120]]function 可以以匿名函数(anonymous function)的方式通过参数传递
function testFun(tab,fun) for k ,v in pairs(tab) do print(fun(k,v)); endend
tab={key1="val1",key2="val2"};testFun(tab,function(key,val)--匿名函数 return key.."="..val;end
--[[key1=val1key2=val2]]Lua函数可以返回多个结果值,比如string.find,其返回匹配串”开始和结束的下标”(如果不存在匹配串返回nil)。在return后列出要返回的值的列表即可返回多值
> s, e = string.find("www.runoob.com", "runoob")> print(s, e)-- 5 10
function maximum (a) local mi = 1 -- 最大值索引 local m = a[mi] -- 最大值 for i,val in ipairs(a) do if val > m then mi = i m = val end end return m, miend
print(maximum({8,10,23,12,5}))-- 23 3Lua 函数可以接受可变数目的参数,和 C 语言类似,在函数参数列表中使用三点 ...表示函数有可变的参数。
function average(...) result = 0 local arg={...} --> arg 为一个表,局部变量 for i,v in ipairs(arg) do result = result + v end print("总共传入 " .. #arg .. " 个数") return result/#argend
print("平均值为",average(10,5,3,4,5,6))--[[总共传入 6 个数平均值为 5.5]]我们也可以通过select("#",...)来获取可变参数的数量:
function average(...) result = 0 local arg={...} for i,v in ipairs(arg) do result = result + v end print("总共传入 " .. select("#",...) .. " 个数") return result/select("#",...)end
print("平均值为",average(10,5,3,4,5,6))--[[总共传入 6 个数平均值为 5.5]]固定参数必须放在变长参数之前
function fwrite(fmt, ...) ---> 固定的参数fmt return io.write(string.format(fmt, ...))end
fwrite("runoob\n") --->fmt = "runoob", 没有变长参数。fwrite("%d%d\n", 1, 2) --->fmt = "%d%d", 变长参数为 1 和 2
--[[runoob12]]通常在遍历变长参数的时候只需要使用 {…},然而变长参数可能会包含一些 nil,那么就可以用 select 函数来访问变长参数了:select(’#’, …) 或者 select(n, …)
- select(’#’, …) 返回可变参数的长度。
- select(n, …) 用于返回从起点 n 开始到结束位置的所有参数列表。
- 调用 select 时,必须传入一个固定实参 selector(选择开关) 和一系列变长参数。如果 selector 为数字 n,那么 select 返回参数列表中从索引 n 开始到结束位置的所有参数列表,否则只能为字符串 #,这样 select 返回变长参数的总数。
function f(...) a = select(3,...) -->从第三个位置开始,变量 a 对应右边变量列表的第一个参数 print (a) print (select(3,...)) -->打印所有列表参数end
f(0,1,2,3,4,5)
--[[22 3 4 5]]thread
在 Lua 里,最主要的线程是协同程序(coroutine)。它跟线程(thread)差不多,拥有自己独立的栈、局部变量和指令指针,可以跟其他协同程序共享全局变量和其他大部分东西。
线程跟协程的区别:线程可以同时多个运行,而协程任意时刻只能运行一个,并且处于运行状态的协程只有被挂起(suspend)时才会暂停。
userdata
userdata 是一种用户自定义数据,用于表示一种由应用程序或 C/C++ 语言库所创建的类型,可以将任意 C/C++ 的任意数据类型的数据(通常是 struct 和 指针)存储到 Lua 变量中调用。
循环
for
重复执行指定语句,重复次数可在 for 语句中控制。
-- 数值for循环-- for的三个表达式在循环开始前一次性求值,以后不再进行求值。-- var 从 exp1 变化到 exp2,每次变化以 exp3 为步长递增 var,并执行一次 **"执行体"**。-- exp3 是可选的,如果不指定,默认为1。for var=exp1,exp2,exp3 do-- <执行体>end
function f(x) print("function") return x*2endfor i=1,f(5) do print(i)end
-- 泛型for循环-- i是数组索引值,v是对应索引的数组元素值。-- ipairs是Lua提供的一个迭代器函数,用来迭代数组。a = {"one", "two", "three"}for i, v in ipairs(a) do print(i, v)endwhile
在条件为 true 时,让程序重复地执行某些语句。执行语句前会先检查条件是否为 true。
repeat…until
重复执行循环,直到 指定的条件为真时为止
IF判断
Lua 编程语言流程控制语句通过程序设定一个或多个条件语句来设定。在条件为 true 时执行指定程序代码,在条件为 false 时执行其他指定代码。
-- 示例1[ 0 为 true ]if(0)then print("0 为 true")end
-- 示例2 [ 定义变量 --]a = 100;--[ 检查条件 --]if( a < 20 )then --[ if 条件为 true 时执行该语句块 --] print("a 小于 20" )else --[ if 条件为 false 时执行该语句块 --] print("a 大于 20" )endprint("a 的值为 :", a)
local a = nillocal b = 0print(a or b) -- 0print(a and b) -- nilprint(not a) -- trueprint(not b) -- false运算符
算数运算符
| + | 加法 | A + B 输出结果 30 |
|---|---|---|
| - | 减法 | A - B 输出结果 -10 |
| * | 乘法 | A * B 输出结果 200 |
| / | 除法 | B / A 输出结果 2 |
| % | 取余 | B % A 输出结果 0 |
| ^ | 乘幂 | A^2 输出结果 100 |
| - | 负号 | -A 输出结果 -10 |
| // | 整除运算符(>=lua5.3) | 5//2 输出结果 2 |
关系运算符
| == | 等于,检测两个值是否相等,相等返回 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。 |
逻辑运算符
| and | 逻辑与操作符。 若 A 为 false,则返回 A,否则返回 B。 | (A and B) 为 false。 |
|---|---|---|
| or | 逻辑或操作符。 若 A 为 true,则返回 A,否则返回 B。 | (A or B) 为 true。 |
| not | 逻辑非操作符。与逻辑运算结果相反,如果条件为 true,逻辑非为 false。 | not(A and B) 为 true。 |
others
| .. | 连接两个字符串 | a..b ,其中 a 为 “Hello ” , b 为 “World”, 输出结果为 “Hello World”。 |
|---|---|---|
| # | 一元运算符,返回字符串或表的长度。 | #“Hello” 返回 5 |
优先级
-- 从高到低^not - (unary)* / %+ -..< > <= >= ~= ==andor-- 除了 ^ 和 .. 外所有的二元运算符都是左连接的。a+i < b/2+1 -- (a+i) < ((b/2)+1)5+x^2*8 -- 5+((x^2)*8)a < y and y <= z -- (a < y) and (y <= z)-x^2 -- -(x^2)x^y^z -- x^(y^z)语法补充
多文件调用
关键字:require
- 运行指定文件,且被调用文件指挥运行一次
- 末尾不带lua,自动匹配lua文件
- 目录层级使用”.“分隔
- 基本路径:
package.path示例:
-- \path\txt_1.luaprint("txt_1 runtime!")
-- txt_2.luarequire("path.txt_1)
-- 设置默认引入包路径package.path = package.path..";./lua/?.lua"
-- 封装包
-- Person.lualocal person = {}function person.run()print("run!")end
-- app.lualocal person = require("Person")person.run()元表
Lua 中的每个值都可以有一个 元表。 这个 元表 就是一个普通的 Lua 表, 它用于定义原始值在特定操作下的行为。 如果你想改变一个值在特定操作下的行为,你可以在它的元表中设置对应域。 例如,当你对非数字值做加操作时, Lua 会检查该值的元表中的 “__add” 域下的函数。 如果能找到,Lua 则调用这个函数来完成加这个操作。
- 在元表中事件的键值是一个双下划线(
__)加事件名的字符串; 键关联的那些值被称为 元方法。 - 使用
setmetatable来替换一张表的元表。 - 元表决定了一个对象在数学运算、位运算、比较、连接、 取长度、调用、索引时的行为。
- 元表还可以定义一个函数,当表对象或用户数据对象在垃圾回收时调用它。
- 对于一元操作符(取负、求长度、位反), 元方法调用的时候,第二个参数是个哑元,其值等于第一个参数。 这样处理仅仅是为了简化 Lua 的内部实现 (这样处理可以让所有的操作都和二元操作一致), 这个行为有可能在将来的版本中移除。 (使用这个额外参数的行为都是不确定的。)
local t = {v=14}local t2 = {10}local addT = { __add = function(i,j) return i.v+1 end, __index = function(table, index) return "null" end -- 类似构造函数 __newindex = function(table,key,value) -- 类似super rawset(table, key,value) end,}local addT2 = { __add = function(i,j) return i[1]+1 end, __index = { a = "a", b = "b" }}setmetatable(t,addT)setmetatable(t2,addT2)print(t+1) --15print(t2+1) -- 11print(t["a"]) -- nullprint(t2["a"]) -- aprint(t2["c"]) --nil面向对象
语法糖使用
local object = { value = 4, add = function(tab, sum) tab.value = tab.value + sum end,}object:add(3)print(object.value) -- 7
-- 实现一个listlist = {}
-- 定义提供的调用接口listmt = { add = function(t, value) table.insert(t.items,value) end, get = function(t, index) return t.items[index] end, remove = function(t, index) if not index then index = #t.items end table.remove(t.items,index) end,}listmt["__index"] = listmt-- 定义构造函数function list.new() local t = { items= {} } setmetatable(t, listmt) return tend-- 对象创建及调用local obj = list.new()obj:add("a")obj:add("b")obj:add("c")print(obj:get(2)) -- b
obj:remove(1)print(obj:get(1)) -- b协程
描述
Lua 支持协程,也叫 协同式多线程。 一个协程在 Lua 中代表了一段独立的执行线程。 然而,与多线程系统中的线程的区别在于, 协程仅在显式调用一个让出(yield)函数时才挂起当前的执行
调用函数coroutine.create 可创建一个协程。 其唯一的参数是该协程的主函数。 create 函数只负责新建一个协程并返回其句柄 (一个 thread 类型的对象); 而不会启动该协程。
调用 coroutine.resume 函数执行一个协程。 第一次调用 coroutine.resume 时,第一个参数应传入 coroutine.create返回的线程对象,然后协程从其主函数的第一行开始执行。 传递给coroutine.resume 的其他参数将作为协程主函数的参数传入。 协程启动之后,将一直运行到它终止或 让出。
协程的运行可能被两种方式终止:
- 正常途径是主函数返回 (显式返回或运行完最后一条指令),
coroutine.resume将返回 true, 并接上协程主函数的返回值。 - 非正常途径是发生了一个未被捕获的错误, 当错误发生时,
coroutine.resume将返回 false 与错误消息。
通过调用coroutine.yield使协程暂停执行,让出执行权。 协程让出时,对应的最近 coroutine.resume函数会立刻返回,即使该让出操作发生在内嵌函数调用中 (即不在主函数,但在主函数直接或间接调用的函数内部)。 在协程让出的情况下,coroutine.resume 也会返回 true, 并加上传给 coroutine.yield 的参数。 当下次重启同一个协程时, 协程会接着从让出点继续执行。 此时,此前让出点处对 coroutine.yield 的调用 会返回,返回值为传给 coroutine.resume的第一个参数之外的其他参数。
示例
-- 创建一个协程co = coroutine.create(function(arg1, arg2) print('create', arg1,arg2) -- 暂停协程 local v1, v2 = coroutine.yield(co, 'yield 111', 'yield 222') print('yield', v1, v2) return 'create'..arg1, 'create'..arg2 end
);
-- 执行协程 直至结束或暂停val1, val2 = coroutine.resume(co, '111', '222')print('resume1', val1, val2)-- 再次执行、或从暂停处继续执行val1, val2 = coroutine.resume(co, '333', '444')print('resume2', val1, val2)
-- 使用 ccoroutine.wrap封装co = coroutine.wrap(function(arg1, arg2) print('create', arg1,arg2) local v1, v2 = coroutine.yield(co, 'yield 111', 'yield 222') print('yield', v1, v2) return 'create'..arg1, 'create'..arg2 end
);val1, val2 = co('111', '222')