4

我有一个由表组成的 lua 表,所以它是二维的:根 -> 子 -> 孙子。

此层次结构的任何级别都不能保证是“类数组”。第一级具有“零间隙”的整数,第二级甚至没有被整数索引(而是被表索引)。

有问题的表是库中的私有结构。我想为图书馆用户提供一种解析其孙辈的方法。我不太关心它们的解析顺序,只要它们都是。

我首先想到的是使用一个接受回调的函数:

-- this scope has access to root 
function eachGrandChild(callback)
  for _,child in pairs(root) do
    for index,grandChild in pairs(child)
      callback(index, grandChild)
    end
  end
end

用法:

-- no access to root, only to eachGrandChild
eachGrandChild(function(index, grandChild) print(index, grandChild) end)

这么多就明白了。

我的问题是:我可以使用迭代器来提供类似的功能吗?

我说的是可以让我这样做的东西:

for index,grandChild in iterator() do
  print(index, grandChild)
end

我一直在考虑这个问题,但我无法破解它。我见过的所有示例都使用数字在每次迭代中轻松“管理迭代器的状态”。由于我没有数字,我有点卡住了。

4

2 回答 2

7

协程使编写这种迭代器变得容易。协程是一个可以暂停和恢复执行的函数,在概念上类似于线程。协程可以包含深度嵌套的循环,从最内层循环产生一个值,然后在恢复时从中断处继续。当它产生时,恢复它的调用者可以接收产生的值。

在您的情况下,转换为产生孙子eachGrandChild的生成器函数。

function eachGrandChild(root)
  for _,child in pairs(root) do
    for index,grandChild in pairs(child) do
      coroutine.yield(index, grandChild)
    end
  end
end

然后用于coroutine.wrap创建一个函数,该函数将为您的生成器创建一个协程,并在每次调用该函数时恢复它。

function grandChildren(t)
    return coroutine.wrap(function() eachGrandChild(t) end)
end

现在你有了你的迭代器:

for key, val in grandChildren(root) do
    print(key, val)
end

在 Lua 中的编程中有一个章节。

于 2012-11-09T01:36:27.310 回答
4

我同意 Mud 的观点,即协程是解决问题的最佳方法。

为了记录,为了比较,我写了一个没有协程的迭代器。

eachGrandChild为每个元素调用第一个函数。它使用一个state变量,包含两个索引(顶级和二级)。

function eachGrandChild(state)
  while state.childIndex ~= nil do
    local child           = root[state.childIndex]
    state.grandChildIndex = next(child, state.grandChildIndex)
    if state.grandChildIndex == nil then
      state.childIndex = next(root, state.childIndex)
    else
      return state.grandChildIndex, child[state.grandChildIndex]                                                                                                                  
    end 
  end 
end

迭代器使用辅助函数初始化:

function grandChildren(root)
  return eachGrandChild, {childIndex = next(root)}
end

现在迭代器可以正常使用了:

for key, val in grandChildren(root) do
    print(key, val)
end

与基于协程的版本相比,eachGrandChild代码行数更多,更难阅读。

于 2012-11-09T06:55:27.613 回答