在 lua 中每次调用使用不同参数重用协程
Reuse coroutine with different arguments per call in lua
我发现重用曾经创建的 coroutine
非常有用。我找到了一个解决方案,它看起来像这样:
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")
除了输出 不是 :
XXX 1
OOO 2
XXX 3
OOO 4
是:
XXX 1
OOO 1
XXX 1
OOO 1
那么是否可以在恢复调用之间将参数更改为 dummyFunc
?
想想这个。协程的工作方式是这样的。当您首先 resume
它们时,您传递给 resume
的参数将成为协程函数的参数。当协程 yield
s 时,它传递给 yield
的参数成为来自您的 resume
调用的 return 值。
然而,第二次你resume
协程,它没有进入仍在执行的函数并改变第一次传递的参数。更改函数局部变量的值将非常粗鲁。
因此,resume
的参数在 之后 第一次调用将是 return 值来自 yield
.
co = coroutine.create(function (f, args)
while f do
f = coroutine.yield(f(args))
end
end)
所以你需要这样做:
co = coroutine.create(function (f, args)
while f do
f, args = coroutine.yield(f(args))
end
end)
但是,如果您想要更灵活的东西,可以处理可变数量的参数,您需要更聪明:
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)
有些人不会理会 capture_args
的东西,只是依赖 {...}
并在其上调用 unpack
。这更安全,因为用户可以将 nil
值放在参数列表中。 ...
将记录所有参数,甚至是嵌入的 nil
s(但不包括尾部参数)。但是,一旦将其放入数组中,数组的长度将基于第一个 nil
值。
使用 capture_args
,由于 select
的一个鲜为人知的特性,您可以获得 实际 参数计数。并且由于 unpack
能够在给定范围内工作,即使范围超过 table 的长度,您也可以有效地存储参数列表。
我可以通过将长度放在 table 中 return 来使 capture_args
更聪明一些。但这对我来说已经足够了。
这里还有第二个问题:你在 dummyFunc
范围内让步,而 dummyFunc
似乎不明白如何处理 yield
的 return 值(即:您下一个 resume
调用的参数)。
不清楚您希望dummyFunc
如何回应它。如果您希望 dummyFunc
的参数因为您恢复它的方式而改变 而 dummyFunc
不知道,那是不会发生的。
我发现重用曾经创建的 coroutine
非常有用。我找到了一个解决方案,它看起来像这样:
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")
除了输出 不是 :
XXX 1
OOO 2
XXX 3
OOO 4
是:
XXX 1
OOO 1
XXX 1
OOO 1
那么是否可以在恢复调用之间将参数更改为 dummyFunc
?
想想这个。协程的工作方式是这样的。当您首先 resume
它们时,您传递给 resume
的参数将成为协程函数的参数。当协程 yield
s 时,它传递给 yield
的参数成为来自您的 resume
调用的 return 值。
然而,第二次你resume
协程,它没有进入仍在执行的函数并改变第一次传递的参数。更改函数局部变量的值将非常粗鲁。
因此,resume
的参数在 之后 第一次调用将是 return 值来自 yield
.
co = coroutine.create(function (f, args)
while f do
f = coroutine.yield(f(args))
end
end)
所以你需要这样做:
co = coroutine.create(function (f, args)
while f do
f, args = coroutine.yield(f(args))
end
end)
但是,如果您想要更灵活的东西,可以处理可变数量的参数,您需要更聪明:
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)
有些人不会理会 capture_args
的东西,只是依赖 {...}
并在其上调用 unpack
。这更安全,因为用户可以将 nil
值放在参数列表中。 ...
将记录所有参数,甚至是嵌入的 nil
s(但不包括尾部参数)。但是,一旦将其放入数组中,数组的长度将基于第一个 nil
值。
使用 capture_args
,由于 select
的一个鲜为人知的特性,您可以获得 实际 参数计数。并且由于 unpack
能够在给定范围内工作,即使范围超过 table 的长度,您也可以有效地存储参数列表。
我可以通过将长度放在 table 中 return 来使 capture_args
更聪明一些。但这对我来说已经足够了。
这里还有第二个问题:你在 dummyFunc
范围内让步,而 dummyFunc
似乎不明白如何处理 yield
的 return 值(即:您下一个 resume
调用的参数)。
不清楚您希望dummyFunc
如何回应它。如果您希望 dummyFunc
的参数因为您恢复它的方式而改变 而 dummyFunc
不知道,那是不会发生的。