Lua 协程中 resume 和 yield 函数的混淆
我正在通过这个 视频教程 学习 Lua。其中有这样一段代码:
co = coroutine.create(function()
for i=1,5 do
print(coroutine.yield(i))
end
end)
print(coroutine.resume(co,1,2))
print(coroutine.resume(co,3,4))
print(coroutine.resume(co,5,6))
print(coroutine.resume(co,7,8))
print(coroutine.resume(co,9,10))
print(coroutine.resume(co,11,12))
输出结果如下:
true 1
3 4
true 2
5 6
true 3
7 8
true 4
9 10
true 5
11 12
true
但是我不理解 yield 和 resume 是如何互相传递参数的,以及为什么 yield 没有输出传递给它的第一组参数 1 和 2 。能否有人解释一下?谢谢!
co = coroutine.create(function()
for i=1,5 do
print(coroutine.yield(i))
end
end)
我们使用以下代码第一次启动协程:
print(coroutine.resume(co,1,2))
它将运行到第一个yield,我们的第一次resume调用将返回true和yield的参数(这里i = 1),这解释了第一行输出。
我们的协程现在被挂起。一旦我们第二次调用resume:
print(coroutine.resume(co,3,4))
您的第一个yield最终返回,当前resume的参数(3,4)将被打印。循环的第二次迭代开始,coroutine.yield(2)被调用,暂停协程,再次使您的最后一个resume返回true,2等等。
因此,在您的示例中,coroutine.resume(co)足以进行第一次调用,因为任何进一步的参数都会丢失。
我们看到这种行为的原因是微妙的,但这与 "进入" 和 "退出" yield 语句不匹配有关。它还与匿名函数内 print 和 yield 调用的顺序有关。
让我们想象一张 print(coroutine.yield(i)) 和迭代执行的图。
在第一次迭代中,我们使用 coroutine.resume 将 1 和 2 传递给协程。这是起始点,所以我们没有从以前的 yield 中提取代码,而是从匿名函数本身的原始调用开始。yield 在 print 中调用,返回 i=1,但未调用 print。该函数退出。
接下来,在暂停一段时间后,我们看到下一个 coroutine.resume 的恢复。该 resume 传递 3 和 4。该函数从最后一个 yield 开始。请记住,在第一次调用 yield 时,print 函数未被调用,而是首先调用了 yield。那么执行返回到 print 中,所以现在调用了 print,但这次返回 3 和 4,因为这些是最新的传输值。该函数再次重复,先调用 yield,再调用 print,返回 i=2。
如果我们进入迭代,我们会更加确定共同模式,这就是我们为什么没有看到 1 和 2 的原因。我们的第一个迭代是一个与相应的 "进入 yield" 不匹配的 "退出 yield"。这对应于协程 co 的第一次执行时间。
我们可能希望最后一个 yield 也不匹配,但区别在于我们会有一个未配对的 "进入" yield,而不是未配对的 "退出" yield,因为循环已经完成。这就解释了为什么我们看到 11 12,随后是 true,而没有任何 "退出 yield"。
这种情况独立于 for 循环内的奇偶性。重要的是 resume 和 yield 对以及它们的处理方式。您必须欣赏,yield 在第一次调用 resume 时不会在函数内返回值,因为该 resume 用于在协程内调用该函数。
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
普通的 Lua 函数有一个入口(用于传入参数),一个出口(用于传出返回值):
local function f( a, b ) print( "arguments", a, b ) return "I'm", "done" end print( "f returned", f( 1, 2 ) ) --> arguments 1 2 --> f returned I'm done将参数放在括号内将其与参数名(本地变量)绑定,列表中作为
return语句的一部分的返回值可以通过在赋值语句的右侧将函数调用表达式放入,或者在大型表达式(例如另一个函数调用)中使用。还有其他调用函数的方法。例如,
pcall()调用函数并捕获可能引发的运行时错误。将参数放在pcall()函数调用中(在函数名称之后)作为参数传递。pcall()也会添加一个额外的返回值,用于表示函数正常退出或通过错误退出。被调用函数内部不变。print( "f returned", pcall( f, 1, 2 ) ) --> arguments 1 2 --> f returned true I'm done您可以使用
coroutine.resume()而不是pcall()调用协程的主函数。参数传递方式和额外的返回值保持不变:local th = coroutine.create( f ) print( "f returns", coroutine.resume( th, 1, 2 ) ) --> arguments 1 2 --> f returns true I'm done但是,在使用协程时,您还可以(临时)退出函数的另一种方式:
coroutine.yield()。您可以通过将其作为参数放入yield()函数调用中使用coroutine.yield()传递值。这些值可以在coroutine.resume()调用的返回值中作为yield()函数调用的返回值而不是正常的返回值在外部检索。但是,您可以通过再次调用
coroutine.resume()重新进入中止的协程。协程在离开的地方继续进行,传递给coroutine.resume()的额外值可以作为先前挂起协程的yield()函数调用的返回值之后作为返回值。local function g( a, b ) print( "arguments", a, b ) local c, d = coroutine.yield( "a" ) print( "yield returned", c, d ) return "I'm", "done" end local th = coroutine.create( g ) print( "g yielded", coroutine.resume( th, 1, 2 ) ) print( "g returned", coroutine.resume( th, 3, 4 ) ) --> arguments 1 2 --> g yielded true a --> yield returned 3 4 --> g returned true I'm done请注意,
yield不必直接放在协程的主函数中,它可以在嵌套的函数调用中。执行跳回到最初(重新)启动协程的coroutine.resume()。现在回答您的问题,为什么第一个
resume()中的1,2没有出现在输出中:您的协程主函数没有列出任何参数,因此忽略所有传递给它的参数(在第一次函数进入时)。同样,由于您的主函数没有返回任何返回值,因此最后的resume()除了指示成功执行的true之外不返回任何额外的返回值。