Lua 脚本

学习视频:

Lua教程-进阶部分 - 4K超清【不定期更新】_哔哩哔哩_bilibili

Lua 教程 | 菜鸟教程 (runoob.com)

1. 环境搭建

1.1 Win 环境下载

Lua在Windows下的安装、配置、运行_lua-language-server win7-CSDN博客

image-20240709144147601

  • 打开 cmd,输入 lua54lua54 -i 即可打开 Lua 交互式编程模式(54 指的是版本是5.4,具体看文件夹里exe的命名)
    • 点击 ctrl+Z 后再回车即可退出该交互式环境

image-20240709144254315

1.2 IDEA 配置 Lua 开发环境

搭建Lua开发环境(Lua解释器+IDEA编译器)_lua ide-CSDN博客

  • IDEA 中安装 Lua 插件:EmmyLua
  • 新建 lua 项目:

image-20240709144830450

  • 设置 SDK:Ctrl+Alt+Shift+S 打开配置SDK,添加 Lua 的SDK 并配置 Lua 的 SDK 安装位置

image-20240709145321935

  • 设置解释器程序

image-20240709145230174

  • 编写 lua 脚本即可运行:Hello.lua

image-20240709150004999

image-20240709170749390

1.3 VSCode 配置 Lua 环境

  • 创建文件夹:Lua_Vscode_code
  • 安装 Lua 语言插件和调试器

image-20240709230353198

  • 设置中搜索 executorMap,点击在 setting.json 中编辑

image-20240709230841290

  • 修改默认 Lua 配置,指定安装包地址,如图所示(没有就直接加)
1
2
3
"code-runner.executorMap": {
"lua": "D:\\lua-5.4.2_Win32_bin\\lua54.exe"
}

image-20240709230927020

  • 运行成功:

image-20240709231014547

2. 基本语法

Lua 基本语法 | 菜鸟教程 (runoob.com)

2.1 注释

  • 变量默认是全局的,不需要声明,赋值后即创建完成
  • 访问未初始化的全局变量得到 nil
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- 单行注释
print("hello")

--[[
多行注释
多行注释
--]]

-- 变量默认是全局的, 不需要声明, 赋值后即创建完成
a = 1
print(a)

-- 访问未初始化的全局变量得到 nil
print(b) -- nil

2.2 数据类型

  • Lua 是动态类型语言,变量不要类型定义,只需要为变量赋值
  • 值可以存储在变量中,作为参数传递或结果返回
1
2
3
4
5
6
7
8
-- 数据类型
print(type("Hello world")) -- string
print(type(10.4*3)) -- number
print(type(print)) -- function
print(type(type)) -- function
print(type(true)) -- boolean
print(type(nil)) -- nil
print(type(type(X))) -- string
  • 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 的创建是通过”构造表达式”来完成,最简单构造表达式是{},用来创建一个空表
  • nil 类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
--[[ nil 类型:
给全局变量或者 table 表里的变量赋一个 nil 值, 等同于把它们删掉
table 可以同时包含数组部分(以整数索引访问)和键值对部分(以字符串或其他非整数类型为键访问)
--]]
tab1 = { key1 = "val1", key2 = "val2", "val3" }
for k, v in pairs(tab1) do
print(k .. " - " .. v)
end

tab1.key1 = nil
for k, v in pairs(tab1) do
print(k .. " - " .. v)
end

-- nil 作比较时应该加上双引号 "
type(X)
print(type(X) == nil) -- false
print(type(X) == "nil") -- true (type(X)实质是返回的 "nil" 字符串, 是一个 string 类型)
  • boolean 类型
1
2
3
4
5
6
7
8
--[[ boolean 类型
false 和 nil 看作 false, 其余均为 true (包括数字0)
--]]
if 0 then
print("数字 0 是 true")
else
print("数字 0 为 false")
end
  • number 类型
1
2
3
4
5
6
7
--[[ number 类型
默认只有 double 类型
--]]
print(type(2)) -- number
print(type(0.2))
print(type(0.2e-1))
print(type(7.8263692594256e-06))
  • string 类型
    • 长度计算可以用 string.len(str)utf8.len(str)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
--[[ string 类型
可以用单引号/双引号
也可以用两个方括号表示一块字符串
--]]
html = [[
<html>
<head></head>
<body>
<a href="http://www.aaa.com/">hhh</a>
</body>
</html>
]]
print(html)

-- 字符串连接使用 ..
print("hhh" .. "aaa") -- hhhaaa

-- 使用 # 计算字符串的长度
len = "www.aaa.com"
print(#len) -- 11
  • table 类型
    • Lua 中并没有专门的数组类型,而是使用一种被称为 “table” 的数据结构来实现数组的功能
    • 可以使用整数索引来访问数组元素,如果指定的索引没有值则返回 nil,除此外我们还可以以负数为数组索引值
    • Lua 提供了元表(是一个特殊的表, 是普通表的扩展功能)允许我们改变 table 的行为,每个行为关联了对应的元方法
      • 使用元表我们可以定义 Lua 如何计算两个 table 的相加操作 a+b
      • 元方法是元表中的特定字段,用于定义表的行为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
--[[ table 表
通过 构造表达式 完成创建, 最简单的构造表达式是 {}
其实是一个关联数组, 数组的索引可以是数字或者是字符串
本质上是一个无序的集合, Lua 的 table 是基于哈希表实现的, 元素的存储顺序可能会因为哈希冲突和哈希表重建等因素而变化
Lua 里表的默认初始索引一般以 1 开始
table 不会固定长度大小, 有新数据添加时 table 长度会自动增长, 没初始的 table 都是 nil
--]]
-- 创建一个空的 table
local tbl1 = {}
-- 直接初始表
local tbl2 = {"apple", "pear", "orange", "grape"}
a = {}
a["key"] = "value"
key = 10
a[key] = 22
a[key] = a[key] + 11
for k, v in pairs(a) do
print(k .. " : " .. v)
end

-- 创建一个数组
local myArray = {10, 20, 30, 40, 50}
-- 添加新元素到数组末尾
myArray[#myArray + 1] = 60
-- 循环遍历数组
for i = 1, #myArray do
print(myArray[i])
end
-- 删除第三个元素
table.remove(myArray, 3)
  • function 函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
--[[ function 函数
--]]
function factorial1(n)
if n == 0 then
return 1
else
return n * factorial1(n - 1)
end
end
print(factorial1(5))
factorial2 = factorial1 -- 函数可以存在变量里
print(factorial2(5))

-- 可以以匿名函数的方式通过参数传递
function testFun(tab,fun) -- 接受一个 table 和一个函数作为参数
for k ,v in pairs(tab) do
print(fun(k,v));
end
end
tab={key1="val1",key2="val2"};
testFun(tab,
function(key,val) -- 匿名函数
return key.."="..val;
end
);
  • 线程
1
2
3
4
5
6
7
8
9
--[[ 线程
在 lua 中的线程实际上是协程, 允许在不同的执行点之间切换, 而无需使用多线程的复杂性和开销
轻量级线程, 它们在单个线程内执行, 并且由程序显式地管理执行的切换点
--]]
co = coroutine.create(function() -- 创建协程
print("Hello from coroutine")
end)
-- 执行协程
coroutine.resume(co) -- Hello from coroutine

2.3 变量

  • Lua 变量有三种类型:全局变量、局部变量、表中的域
    • Lua 中的变量全是全局变量,哪怕是语句块或是函数里,除非用 local 显式声明为局部变量
    • 局部变量的作用域为从声明位置开始到所在语句块结束
    • 变量的默认值均为 nil
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
--[[全局变量 VS 局部变量
--]]
a = 5 -- 全局变量
local b = 5 -- 局部变量

function joke()
c = 5 -- 全局变量
local d = 6 -- 局部变量
end

joke()
print(c,d) --> 5 nil

do
local a = 6 -- 局部变量
b = 6 -- 对局部变量重新赋值
print(a,b); --> 6 6
end

print(a,b) --> 5 6

-- 赋值语句
a, b, c = 0, 1
print(a,b,c) --> 0 1 nil

a, b = a+1, b+1, b+2 -- value of b+2 is ignored
print(a,b) --> 1 2

a, b, c = 0
print(a,b,c) --> 0 nil nil

-- 索引, 对 table 的索引使用 [] 或 .
t = {key1="key1", "hh"}
print(t[1]) -- hh
print(t.key1) -- key1 当索引为字符串类型时的一种简化写法

2.4 运算符

  • 算术、关系、逻辑、其他运算符
  • 算术运算符:+、-、*、/、%、^、//(整除,>=lua5.3)
  • 关系运算符:==、~=(不等于)、>、<、>=、<=
  • 逻辑运算符:and or not
  • 其他运算符:..(连接两个字符串)、#(返回字符串或表的长度)
  • 优先级:
1
2
3
4
5
6
7
8
^
not - (unary)
* / %
+ -
..
< > <= >= ~= ==
and
or
  • 代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
--[[ 运算符
--]]
-- 算术运算符
a = 21
b = 10
c = a + b
print("Line 1 - c 的值为 ", c ) -- 31
c = a - b
print("Line 2 - c 的值为 ", c ) -- 11
c = a * b
print("Line 3 - c 的值为 ", c ) -- 210
c = a / b
print("Line 4 - c 的值为 ", c ) -- 2.1
c = a // b
print("Line 5 - c 的值为 ", c ) -- 2
c = a % b
print("Line 6 - c 的值为 ", c ) -- 1
c = a^2
print("Line 7 - c 的值为 ", c ) -- 441.0
c = -a
print("Line 8 - c 的值为 ", c ) -- -21

-- 关系运算符
a = 21
b = 10
if( a ~= b )
then
print("Line 9 - a 不等于 b" )
else
print("Line 9 - a 等于 b" )
end

-- 逻辑运算符 and or not
a = false
b = true
if ( a and b )
then
print("a and b - 条件为 true" )
else
print("a and b - 条件为 false" )
end

-- 其他运算符 ..(连接两个字符串)、#(返回字符串或表的长度)
a = "Hello "
b = "World"
print("连接字符串 a 和 b ", a..b ) -- Hello World
print("b 字符串长度 ", #b)
print("字符串 Test 长度 ", #"Test" )
print("网址长度 ", #"www.run.com" )
  • 三元操作符:举例

    • (szMod == nil) and false or szMod Lua 中的三元操作符(条件运算符)模式,用于根据条件选择不同的值

    • (szMod == nil):检查 szMod 是否为 nil

      • 如果 szModnil,则表达式结果为 true
      • 否则表达式结果为 false
    • and false:如果 (szMod == nil)true,则返回 false

    • or szMod:如果 and 左侧为 false(即 (szMod == nil)false),则返回 szMod 的值

3. 控制语句

3.1 循环

Lua 语言提供了以下几种循环处理方式:

循环类型 描述
while 循环 在条件为 true 时,让程序重复地执行某些语句。执行语句前会先检查条件是否为 true。
for 循环 重复执行指定语句,重复次数可在 for 语句中控制。
repeat…until 重复执行循环,直到 指定的条件为真时为止
循环嵌套 可以在循环内嵌套一个或多个循环语句(while do … end;for … do … end;repeat … until;)
  • 代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
--[[ 循环
--]]
-- while 循环
a = 10
while( a < 20 )
do
print("a 的值为:", a)
a = a+1
end

-- for 循环
-- 数值 for 循环
for i=10,1,-1 do
print(i)
end
-- 泛型 for 循环
a = {"one", "two", "three"}
for i, v in ipairs(a) do -- ipairs是Lua提供的一个迭代器函数, 用来迭代数组
print(i, v)
end

-- repeat...until 循环
--[ 变量定义 --]
a = 10
--[ 执行循环 --]
repeat
print("a的值为:", a)
a = a + 1
until( a > 15 )

-- 循环嵌套
j=2
for i=2,10 do
for j=2,(i/j),2 do
if(not(i%j))
then
break
end
if(j > (i/j))then
print("i 的值为:",i) -- 8 9 10
end
end
end

3.2 选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
--[[ 选择语句
--]]
-- if 语句
a = 10;
if( a < 20 )
then
--[ if 条件为 true 时打印以下信息 --]
print("a 小于 20" );
end
print("a 的值为:", a);

-- if..else 语句
a = 100;
if( a < 20 ) then
--[ if 条件为 true 时执行该语句块 --]
print("a 小于 20" )
elseif (a == 20) then
print("a 等于 20")
else
--[ if 条件为 false 时执行该语句块 --]
print("a 大于 20" )
end
print("a 的值为 :", a)

4. 函数

  • 函数默认为全局函数,若需要设置函数为局部函数需要使用关键字 local
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
-- 函数
--[[ 函数返回两个值的最大值 --]]
function max(num1, num2)
if (num1 > num2) then
result = num1;
else
result = num2;
end

return result;
end
-- 调用函数
print("两值比较最大值为 ",max(10,4))
print("两值比较最大值为 ",max(5,6))
-- 可以将函数作为参数传递给函数
myPrint = function(param)
print("这是打印函数 - ##", param, "##")
end

function add(num1,num2,functionPrint)
result = num1 + num2
-- 调用传递的函数参数
functionPrint(result)
end
myPrint(10)
-- myPrint 函数作为参数传递
add(2,5,myPrint)
-- 可变参数
function average(...)
result = 0
local arg={...} --> arg 为一个表,局部变量
for _,v in ipairs(arg) do
result = result + v
end
print("总共传入 " .. #arg .. " 个数") -- 总共传入 6 个数
return result/#arg
end
print("平均值为",average(10,5,3,4,5,6)) -- 平均值为 5.5
-- 几个固定参数加上可变参数,固定参数必须放在变长参数之前
function fWrite(fmt, ...) ---> 固定的参数fmt
return io.write(string.format(fmt, ...))
end
fWrite("run\n") --->fmt = "run\n", 没有变长参数, 输出 run\n
fWrite("%d%d\n", 1, 2) --->fmt = "%d%d", 变长参数为 1 和 2, 输出 12\n

5. 多文件调用

  • 模块类似于一个封装库,从 Lua 5.1 开始,Lua 加入了标准的模块管理机制,可以把一些公用的代码放在一个文件里,以 API 接口的形式在其他地方调用,有利于代码的重用和降低代码耦合度
  • Lua 的模块是由变量、函数等已知元素组成的 table,因此创建一个模块很简单,就是创建一个 table,然后把需要导出的常量、函数放入其中,最后返回这个 table 就行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
-- 文件名为 module.lua
-- 定义一个名为 module 的模块
module = {}

-- 定义一个常量
module.constant = "这是一个常量"

-- 定义一个函数
function module.func1()
io.write("这是一个公有函数!\n")
end

local function func2()
print("这是一个私有函数!")
end

function module.func3()
func2()
end

return module
  • require 函数:用来加载模块。要加载一个模块,只需要简单地调用就可以了
    • 可以运行指定的文件,末尾不带扩展名
    • 目录层级用 . 分割 require("path.hello2")
    • 只会运行一次,每次调用的返回值都是第一次调用的结果
1
2
3
4
5
6
7
-- 文件名为 main.lua
local module = require "module"

-- 调用公有函数
module.func1() -- 输出:这是一个公有函数!(没有自动换行,因为手动添加了 \n)
module.func3() -- 输出:这是一个私有函数!(自动换行)
print(module.constant) -- 输出:这是一个常量(自动换行)
  • 查找时从 package.path 里查找
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- test.lua 文件
_G.count = 1

require("hello")
require("hello")
require("hello")
local r = require("hello")
print(r)
print(_G.count) -- 2

print(package.path)
-- 路径是从 package.path 里查找的
-- 此处添加路径path文件夹下的路径至 package.path, 就可以直接 require hello2.lua, 不用再写路径了
package.path = package.path .. ";./path/?.lua"
require("hello2")

-- hello.lua 文件
_G.count = _G.count + 1

local name = "world"
print("Hello, " .. name) -- Hello, world
return "done"
  • 多次调用:若想多次调用某个 lua 文件里的函数,可以使用 table,将函数放在 table 里下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- test.lua 文件
package.path = package.path .. ";./path/?.lua"
local hello2 = require("hello2")
hello2.say() -- hello2 world

-- path/hello2.lua 文件
local hello2 = {}

-- say 函数直接位于 hello2 这个 table 下面
function hello2.say()
print("hello2 world")
end

return hello2;

6. 迭代器

  • 普通迭代:下标到table长度
1
2
3
4
5
local t = {"a", "b", "c", "d"}

for i = 1, #t do
print(i, t[i]) -- 1 a 2 b 3 c 4 d
end
  • ipairs 迭代:适用于纯数字下标且按顺序的迭代
    • 对于不连续的数字下标的迭代,只会遍历到中断的位置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
for i, j in ipairs(t) do
print(i, j) -- 1 a 2 b 3 c 4 d
end


local ta = {
[1] = "a",
[2] = "b",
[4] = "c"
}

for i, j in ipairs(ta) do
print(i, j) -- 1 a 2 b
end
  • pairs 迭代:可以迭代所有的下标
    • 常用于字符串下标的 table
    • 其内部使用了 next 函数, 但是每次输出结果不同(因为底层是哈希表),可以利用这个函数快速判断 table 是否为空
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
t = {
apple = "a",
banana = "b",
eraser = "c"
}
for i,j in pairs(t) do
print(i, j) -- banana b eraser c apple a
end

-- table 的键值对是存储在哈希表中的, 存储顺序是不确定的
t = {
a = 1,
b = 2,
c = 3
}
print(next(t)) -- a 1
-- 第二个参数是表中的某个键
-- next 返回该键的下一个键及其关联的值
-- 每次结果不同, 返回的顺序不同, 因为底层实现是哈希表
print(next(t, "a")) -- b 2

t = {}
print(next(t)) -- nil

7. 字符串库

Lua 5.3 参考手册

  • 存储的是一串数字,lua 里的字符串可以存储任何 Byte 值,只要是一个字节的数就可以存
  • 字符串的索引从 1 开始
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
local s = "123456789"
-- print(s:byte(1))
print(string.byte(s, 1)) -- 查看字符串某一位的原始值, 此处输出 49

-- string.byte 的逆运算是 string.char
-- 0x35 是十六进制表示, 等于十进制的 53, 对应的 ASCII 字符是 '5'
print(string.char(0x35, 0x36, 0x37)) -- 567

local b = string.char(0, 0, 1, 2, 3)
print(b:byte(1, -1)) -- 0 0 1 2 3

-- 格式化字符串: string.format (formatstring, ···)
local f = string.format("%d, %d", 1, 2) -- 1, 2
print(f)

-- 长度: string.len (s)
print(string.len(s)) -- 9

-- 子字符串 lua 的字符串是左闭右闭区间
-- 或 print(string.sub(s, 4))
print(s:sub(4)) -- 456789
  • 正则:string.find()string.match()
    • 前者返回找到的起始和终止位置,后者返回找到的目标字符串
1
2
3
-- 正则
print(string.find(s, "123")) -- 1 3
print(string.match(s, "123")) -- 123

image-20240710101043801

image-20240710101558385

image-20240710101529103

  • string.gsub() 用于替换,string.gmatch() 用于匹配多个
1
2
3
4
5
6
7
8
9
-- 替换
-- 此处将字符串中的所有数字替换成x, 返回替换后的字符串以及替换的字符个数
print(string.gsub(s, "%d", "x")) -- xxxxxxxxx 9

-- 匹配多个, 类似迭代器
s = "hello world from Lua"
for w in string.gmatch(s, "%a+") do
print(w) -- hello world from Lua
end

8. 元表及元方法

  • __add 加法重载
  • __index 索引访问
  • __newindex 索引赋值

image-20240710103730927

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
-- 元表和元方法
local t = {a = 1}
-- print(t + 1) 不合法的操作
-- print(t["abc"]) 返回 nil

-- 使用元表
local mt = {
-- 类似运算符重载?
__add = function (a, b)
-- 当对 t 进行加法操作时,如果 t 作为第一个操作数且 t 中有键 a,返回 t.a + b
return a.a + b
end,

-- 访问不存在的索引
__index = {
abc = 123
},

-- 索引赋值
__newindex = function (t, k, v)
rawset(t, k, v)
end
}
setmetatable(t, mt)
print(t + 1) -- 2
print(t["abc"]) -- 123
-- 直接给 t 赋值会进入到 newIndex 里, 所以使用 rawset 进行赋值, 绕过触发元方法
t["abc"] = 1
print(t["abc"]) -- 1
  • 语法糖:
1
2
3
4
5
6
7
8
9
t = {
a = 0,
add = function (tab, sum)
tab.a = tab.a + sum
end
}

t.add(t, 10) -- 语法糖, 可直接 t:add(10)
print(t.a) -- 10

9. 面向对象

  • table 是一个标准库表,它包含了一些用于操作 Lua 表的函数,比如 table.inserttable.remove

  • 举例:

    • 对象名 bag
    • 构造函数 new
    • 装入东西 put
    • 拿出东西 take
    • 列出所有东西 list
    • 清空 clear
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
local bag = {}
local bagmt = {
put = function (self, item)
table.insert(self.items, item)
end,

-- take 方法从 items 表中取出最后一个元素
take = function (self)
return table.remove(self.items)
end,

list = function (self)
return table.concat(self.items, ",")
end,

clear = function (self)
self.items = {}
end
}
-- 将 bagmt 设为元表,并将 __index 指向自己
bagmt["__index"] = bagmt
-- 定义 bag 的构造函数
function bag.new()
local instance = {
items = {}
}
-- 设置元表,使得未定义的元素从 bagmt 中查找
setmetatable(instance, bagmt)
return instance
end

-- 创建 bag 对象 b
local b = bag.new()
-- 调用 b 的 put 方法
b:put("apple")
b:put("apple")
b:put("apple")
b:put("apple")
print(#(b.items)) -- 4
print(b:list()) -- apple,apple,apple,apple
print(b:take()) -- apple
b:clear()
print(#(b.items)) -- 0

10. 协程(单线程)

Lua 5.3 Reference Manual

  • 一个 lua 虚拟机只是一个单线程,并不是多线程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- 创建协程
co = coroutine.create(function ()
print("hello world")
-- 暂停调用协程的执行
local r1, r2, r3 = coroutine.yield(1, 2, 3)
print("inside", coroutine.status(co)) -- inside running 运行
print("continue run~~", r1, r2, r3)
end)

print(type(co)) -- thread 类型

-- 以字符串形式返回协程的状态
print("1", coroutine.status(co)) -- 1 suspended 暂停
-- 运行协程
coroutine.resume(co) -- hello world
coroutine.resume(co, 4, 5, 6) -- continue run~~ 4 5 6
print("2", coroutine.status(co)) -- 2 dead 死掉

-- 使用 wrap 创建协程, 相当与是一个函数
local cor = coroutine.wrap(function ()
print("hello world")
end)
-- 直接使用
cor() -- hello world