在书《Lua程序设计(第4版)》的协程一章,第273-274页,书上有个例子,让我困惑不已,后来把之前看到的一篇博客——Lua的协程和协程库详解 反复看了两遍,自己动手写了demo测试,才解开心中的疑惑,特此记录,以帮助同样遇到困惑的朋友。

函数coroutine.resume (co [, val1, ···])用来启动或再次启动一个协程,使其由挂起状态变成运行状态。
resume函数相当于在执行协程中的方法。参数Val1…是执行协程co时传递给协程的方法。
  1)、首次执行协程co时,参数Val1…会传递给协程co的函数;
  2)、再次执行协程co时,参数Val1…会作为给协程co中上一次yeild的返回值。
  这是协程的核心。如果没理解也不用急,继续往下看,稍后我会详细解释。

resume函数返回什么呢?有3种情况:   
  1)、如果协程co的函数执行完毕,协程正常终止,resume 返回 true和函数的返回值。
  2)、如果协程co的函数执行过程中,协程让出了(调用了yeild()方法),那么resume返回true和协程中调用yeild传入的参数。
  3)、如果协程co的函数执行过程中发生错误,resume返回false与错误消息。

可以看到resume无论如何都不会导致程序崩溃。它是在保护模式下执行的。

函数coroutine.yield (···),使正在执行的函数挂起。
  传递给yeild的参数会作为resume的额外返回值。同时,如果对该协程不是第一次执行resume,resume函数传入的参数将会作为yield的返回值。

书上的例子是这样:
例一

co = coroutine.create(function(x)
	print("co1", x)
	print("co2", coroutine.yield())
end)

coroutine.resume(co, "hi")
coroutine.resume(co, 4, 5)

运行结果:

co1	hi
co2	4	5

看到这里,貌似没有问题。
但是如果是这样:
例二

co = coroutine.create(function(x)
	print("co1", x)
	print("co2", coroutine.yield(1, 2))
end)

coroutine.resume(co, "hi")
coroutine.resume(co, 4, 5)

运行结果:

co1	hi
co2	4	5

明明这里有coroutine.yield(1, 2),这个参数1和2,怎么好像没生效一样?

不急,我们来看例三:

co = coroutine.create(function(x)
	print("co1", x)
	print("co2", coroutine.yield(1, 2))
end)

print(coroutine.resume(co, "hi"))
print(coroutine.resume(co, 4, 5))

运行结果:

co1	hi
true	1	2
co2	4	5
true

1和2出现了,为了更好地解释,我们将其改成功能相同的例四:

co = coroutine.create(function(x)
	print("co1", x)
	ret1, ret2 = coroutine.yield(1, 2)
	print("co2", ret1, ret2)
end)

print(coroutine.resume(co, "hi"))
print(coroutine.resume(co, 4, 5))

运行结果和例三相同,这时候,我们再来解释,就清楚了。

1. coroutine.resume(co, “hi”)
2. 此时是第一个resume,参数会直接传到到co = coroutine.create(function(x)
 print(“co1”, x),输出co1 hi,3. 继续执行ret1, ret2 = coroutine.yield(1, 2),先看右边coroutine.yield(1, 2),这时候程序在这里返回给resume,返回值为true 1 2,print(coroutine.resume(co, “hi”))执行print,打印出true 1 2
4. coroutine.resume(co, 4, 5),第二个coroutine.resume来了,从ret1, ret2 = coroutine.yield(1, 2)开始执行,上一步coroutine.yield(1, 2)已经返回给第一个resume了,此时的coroutine.yield获得的参数是coroutine.resume(co, 4, 5)中的4和5,所以ret1, ret2 = 4, 5
 print(“co2”, ret1, ret2)打印出的co2 4 55. 至此co = coroutine.create(function(x) 中间省略 end),这里的function(x)已经全部执行完毕,co正常结束,返回true,除此外没有其他返回值,print(coroutine.resume(co, 4, 5)),执行print函数,打印出true。

我们将它拆解开,才完全理清了参数传递过程。原来书中写的例子有些不清不楚,看来一个好的例子能更好地释疑。