在 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 的参数将成为协程函数的参数。当协程 yields 时,它传递给 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 值放在参数列表中。 ... 将记录所有参数,甚至是嵌入的 nils(但不包括尾部参数)。但是,一旦将其放入数组中,数组的长度将基于第一个 nil 值。

使用 capture_args,由于 select 的一个鲜为人知的特性,您可以获得 实际 参数计数。并且由于 unpack 能够在给定范围内工作,即使范围超过 table 的长度,您也可以有效地存储参数列表。

我可以通过将长度放在 table 中 return 来使 capture_args 更聪明一些。但这对我来说已经足够了。


这里还有第二个问题:你在 dummyFunc 范围内让步,而 dummyFunc 似乎不明白如何处理 yield 的 return 值(即:您下一个 resume 调用的参数)。

不清楚您希望dummyFunc如何回应它。如果您希望 dummyFunc 的参数因为您恢复它的方式而改变 dummyFunc 不知道,那是不会发生的。