作为迭代器的lua协程:不能恢复死的协程



那里,

我修改了Lua 5.0在线文档中的"perm"示例:http://www.lua.org/pil/9.3.html.我所做的是将__call()元方法重新指向perm()函数。但它只起作用一次,据报道"无法恢复死亡的郊游"。知道为什么它不起作用吗?

function permgen (a, n)
  if n == 0 then
 coroutine.yield(a)
  else
    for i=1,n do
      -- put i-th element as the last one
      a[n], a[i] = a[i], a[n]
      -- generate all permutations of the other elements
      permgen(a, n - 1)
      -- restore i-th element
      a[n], a[i] = a[i], a[n]
    end
  end
end
function perm (a)
  local n = table.getn(a)
  return coroutine.wrap(function () permgen(a, n) end)
end
K = {"a","b","c"}

for p in perm(K)  do
   print(p[1],p[2],p[3])
end

for p in perm(K)  do
   print(p[1],p[2],p[3])
end
-- everything above is copied from the Lua online document,
-- my modification is the following
setmetatable(K,{__call=perm(K)})
for p in K  do
   print(p[1],p[2],p[3])
end
-- cannot repeat!
-- perm.lua:44: cannot resume dead coroutine
for p in K  do
   print(p[1],p[2],p[3])
end

`

发生这种情况是因为您调用perm(K)一次并将结果分配给__call元方法。然后使用一次(通过执行in K),就完成了perm调用返回的协同程序的执行。当你第二次尝试这样做时,协同程序已经"死"了,这就触发了错误。

你需要做的是检测协同程序是否已经死了,并重新创建它。由于你不能用coroutine.wrap做到这一点,你需要用coroutine.create使用稍微修改过的解决方案。像这样的东西可能会起作用:

function perm (a)
  local n = table.getn(a)
  local co = coroutine.create(function () permgen(a, n) end)
  return function ()   -- iterator
    if coroutine.status(co) == 'dead' then co = coroutine.create(function () permgen(a, n) end) end
    local code, res = coroutine.resume(co)
    if not code then return nil end
    return res
  end
end

它在恢复之前检查协程的状态,如果它已经是dead,则使用相同的参数从头开始重新创建它。

最新更新