我该如何在Lua中创建一个二维表的迭代器?

我有一个由表制成的 Lua 表,因此它是二维的:根 → 子 → 孙子。

这个层次结构中的任何一级都不能保证是“类似数组的”。第一层具有带有“零间隙”的整数,第二层甚至不是由整数(而是由表)索引的。

所讨论的表是库中的一个私有结构。我想为库用户提供一种解析其孙子的方式。我不太在乎它们被解析的顺序,只要它们全部都解析了。

我想到的第一件事是使用接受回调的函数:

-- 这个作用域有 root 的访问权限
function eachGrandChild(callback)
  for _,child in pairs(root) do
    for index,grandChild in pairs(child)
      callback(index, grandChild)
    end
  end
end

用法:

-- 没有访问 root,只有访问 eachGrandChild
eachGrandChild(function(index, grandChild) print(index, grandChild) end)

这一部分被理解了。

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

我说的是允许我这样做的东西:

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

我已经思考了一段时间,但我无法破解它。我看到的所有示例都使用数字轻松“管理迭代器状态”进行每次迭代。由于我没有数字,我有点卡住了。

点赞
用户501459
用户501459

协同程序 使编写这种类型的迭代器变得容易。协同程序是一个函数,其执行可以被挂起和恢复,概念上像线程。协同程序可以包含深层嵌套的循环,在内层循环中产生一个值,然后在恢复时从其离开的地方继续执行。当它暂停时,恢复它的调用者可以接收产生的值。

针对您的情况,将 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-09 01:36:27
用户1008957
用户1008957

我同意 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-09 06:55:27