我是通过这个视频教程学习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但是我不明白产量和简历是如何互相传递参数的,为什么产量没有输出第一个1,2的简历传递给它,有人能解释一下吗?谢谢
发布于 2016-06-28 12:11:02
普通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()来调用coroutine的主函数。传递参数的方式和额外的返回值保持不变:
local th = coroutine.create( f )
print( "f returns", coroutine.resume( th, 1, 2 ) )
--> arguments 1 2
--> f returns true I'm done但是,有了协同,您就可以(暂时)退出函数:coroutine.yield()。您可以通过coroutine.yield()将值作为参数传递到yield()函数调用中。这些值可以作为coroutine.resume()调用的返回值而不是普通的返回值在外部检索。
但是,您可以通过再次调用coroutine.resume()重新输入已生成的协同。coroutine在停止的地方继续,传递给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注意,产量不需要直接在主函数中的协同线,它可以在一个嵌套函数调用。执行跳回(重新)启动协同线的coroutine.resume()。
现在来问为什么输出中没有出现来自第一个1, 2的resume():您的coroutine函数没有列出任何参数,因此忽略了传递给它的所有参数(在第一个函数条目上)。同样,由于主函数不返回任何返回值,最后一个resume()除了表示成功执行的true之外,不返回任何额外的返回值。
发布于 2016-06-28 12:16:53
co = coroutine.create(function()
for i=1,5 do
print(coroutine.yield(i))
end
end)我们第一次使用以下方法启动协同线:
print(coroutine.resume(co,1,2))它将一直持续到第一次屈服。我们的第一个简历调用将返回true和收益率参数(这里i= 1),这说明了第一条输出线。
我们的协同线现在暂停了。一旦我们第二次调用简历:
print(coroutine.resume(co,3,4))您的第一个收益最终返回和您的当前简历(3,4)的参数将打印出来。for循环第二次迭代开始,coroutine.yield(2)被调用,它支持协同线,这将再次使您的最后一次简历返回为真,2等等
因此,实际上,在您的示例中,coroutine.resume(co)对于第一个调用就足够了,因为任何进一步的参数都会丢失。
发布于 2020-05-27 00:08:58
我们看到这种行为的原因是微妙的,但这与“输入”和“退出”yield语句的不匹配有关。它还与匿名函数中调用print和yield的顺序有关。
让我们想象一下print(coroutine.yield(i))执行与迭代的关系图。
在第一次迭代中,我们让coroutine.resume将1和2传递给协同线。这是起始点,所以我们不是从(以前的 yield )中提取的,而是匿名函数本身的原始调用。在打印中调用yield,返回i=1,但不调用print。函数退出。
下面是函数挂起一段时间,然后才能看到下一个coroutine.resume、.This、resume、passes、3和4恢复。函数在最后一次 yield中获得。还记得print函数没有被调用,因为第一个yield首先被调用并退出了程序?执行在print内部返回,所以现在调用print,但这次返回3和4,因为这是要传输的最新值。函数再次重复,在print之前调用print,然后返回i=2。
如果我们继续迭代,我们将更确切地了解为什么我们没有看到1和2的模式。我们的第一次迭代是“退出”产量,而不是对应的“输入产量”。这相当于协同线co的第一次执行。
我们可能期望最后一个yield也不成对,但区别是我们将有一个“输入”yield,它是未配对的,而不是一个“退出”的yield,它是未配对的。这是因为循环已经完成了。这解释了为什么我们看到11 12后面跟着true,没有“退出”yield返回。
这种情况与内部for循环的奇偶性无关。唯一重要的是resume和yield对以及它们的处理方式。您必须意识到,yield不会在resume的第一次调用中返回函数中的值,该值最初用于调用协同线内的函数。
https://stackoverflow.com/questions/38069751
复制相似问题