I found it really useful to reuse a once created coroutine
. I found a solution to that and it looks like so:
co = coroutine.create(function (f, args)
while f do
f = coroutine.yield(f(args))
end
end)
function dummyFunc(data)
print("XXX "..data)
coroutine.yield()
print("OOO "..data)
end
coroutine.resume(co, dummyFunc, "1")
coroutine.resume(co, dummyFunc, "2")
coroutine.resume(co, dummyFunc, "3")
coroutine.resume(co, dummyFunc, "4")
That work like a charm except the output is not:
XXX 1
OOO 2
XXX 3
OOO 4
It is:
XXX 1
OOO 1
XXX 1
OOO 1
So is it possible to change the arguments to the dummyFunc
between the resume calls?
Think about this. The way coroutines work is like this. When you first resume
them, the arguments you pass to resume
become the arguments to the coroutine's function. When the coroutine yield
s, the arguments it passes to yield
become the return values from your resume
call.
However, the second time you resume
the coroutine, it does not reach into the still executing function and change the arguments that were pass in the first time. It would be exceedinly rude to change the value of variables local to the function.
Therefore, the arguments to resume
on calls after the first call will be the return values from yield
.
co = coroutine.create(function (f, args)
while f do
f = coroutine.yield(f(args))
end
end)
So you'd need to do this:
co = coroutine.create(function (f, args)
while f do
f, args = coroutine.yield(f(args))
end
end)
However, if you want something more flexible, that can do variable numbers of arguments, you'll need to be cleverer:
co = coroutine.create(function (...)
local function capture_args(...)
return {...}, select("#", ...)
end
local tbl, len = capture_args(...)
local f = tbl[1]
while f do
tbl, len = capture_args(coroutine.yield(f(unpack(tbl, 2, len))
f = tbl[1]
end
end)
Some people wouldn't bother with the capture_args
stuff, simply relying on {...}
and calling unpack
on it. This is safer because users can put nil
values in parameter lists. ...
will record all of the parameters, even embedded nil
s (but not trailing ones). However, once you put it into an array, the length of the array is based on the first nil
value.
Using capture_args
, you can get the actual parameter count thanks to a little-known-feature of select
. And thanks to the ability of unpack
to work on a given range, even if the range exceeds the length of the table, you can effectively store a parameter list.
I could probably make capture_args
a bit cleverer by putting the length in the table it returns. But this is good enough for me.
There is a second problem here: you are yielding within dummyFunc
, and dummyFunc
does not seem to understand what to do with yield
's return values (ie: the parameters to your next resume
call).
It's not clear how you want dummyFunc
to respond to it. If you wanted dummyFunc
's parameters to change because of how you resumed it without dummyFunc
knowing about it, that's not going to happen.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With