4

テーブルで構成された lua テーブルがあるので、ルート -> 子 -> 孫の 2 次元です。

この階層のどのレベルも「配列のようなもの」であるとは限りません。最初のレベルには「ギャップがゼロ」の整数があり、2 番目のレベルは整数によってもインデックス付けされていません (ただし、テーブルによって)。

問題のテーブルは、lib 内のプライベート構造です。ライブラリのユーザーが孫を解析する方法を提供したいと考えています。それらがすべて解析されている限り、それらが解析される順序についてはあまり気にしません。

私が最初に考えたのは、コールバックを受け入れる関数を使用することでした:

-- 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は各要素に対して呼び出されます。state2 つのインデックス (トップ レベルと 2 番目のレベル) を含む変数を使用します。

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 に答える