この初版は Lua 5.0 用に書かれました。後続バージョンにも依然として関連性はありますが、いくつかの違いがあります。
第 4 版では Lua 5.3 を対象として おり、Amazon や他の書店で購入できます。
本の購入により、Lua プロジェクトのサポートにも協力することになります。
![]() |
Lua によるプログラミング | ![]() |
パート I. 言語 第 9 章. コルーチン |
ループのイテレータを、生産者コンシューマーのパターンのかなり具体的な例と見なすことができます。イテレータは、ループの本文によって消費される項目を生成します。したがって、イテレータの記述にコルーチンを使用するのは適切なようです。実際、コルーチンは、このタスクに強力なツールを提供します。ここでも、重要な機能は、呼び出し側と呼び出し先の関係を逆転できることです。この機能により、イテレータへの連続的な呼び出し間に状態を保持する方法を心配せずにイテレータを作成できます。
この種の使用を説明するために、指定された配列のすべての順列を走査するためのイテレータを作成します。そういったイテレータを直接記述するのは簡単なタスクではありませんが、それらのすべての順列を生成する再帰関数を作成するのは難しくありません。この考え方はシンプルです。すべての配列の要素を順番に最後の位置に配置し、残りの要素のすべての順列を再帰的に生成します。コードは次のとおりです
function permgen (a, n) if n == 0 then printResult(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これが機能していることを確認するために、適切な
printResult
関数を定義し、適切な引数を使用して permgen
を呼び出す必要がありますfunction printResult (a) for i,v in ipairs(a) do io.write(v, " ") end io.write("\n") end permgen ({1,2,3,4}, 4)
ジェネレーターの準備ができたら、イテレータに変換するのは自動的なタスクになります。まず、printResult
を yield
に変更します
function permgen (a, n) if n == 0 then coroutine.yield(a) else ...次に、ジェネレーターがコルーチン内で実行されるように工場を定義し、イテレータ関数を生成します。イテレータは、次の順列を生成するためにコルーチンを再開するだけです
function perm (a) local n = table.getn(a) local co = coroutine.create(function () permgen(a, n) end) return function () -- iterator local code, res = coroutine.resume(co) return res end endその機能が整えば、for ステートメントを使って配列のすべての順列を反復処理することは簡単です
for p in perm{"a", "b", "c"} do printResult(p) end --> b c a --> c b a --> c a b --> a c b --> b a c --> a b c
perm
関数は、対応するコルーチンの resume
呼び出しを関数内にまとめてパックする、Lua で一般的なパターンを使用します。このパターンは非常に一般的なため、Lua はこれに対応する特別な関数である coroutine.wrap
を提供します。create
と同様に、wrap
は新しいコルーチンを作成します。 create
とは異なり、wrap
はコルーチン自体を返しません。代わりに、呼び出し時にコルーチンを再開する関数を返します。元の resume
とは異なり、その関数は最初の結果としてエラーコードを返しません。代わりに、エラーが発生するとエラーを送出します。 wrap
を使用すると、perm
を次のように記述できます
function perm (a) local n = table.getn(a) return coroutine.wrap(function () permgen(a, n) end) end
通常、coroutine.wrap
は coroutine.create
よりも使いやすくなります。コルーチンから必要な、つまり再開するための関数が得られます。ただし、柔軟性は低くなります。 wrap
で作成されたコルーチンの状態を確認する方法はありません。さらに、エラーを確認することはできません。
著作権 © 2003–2004 Roberto Ierusalimschy。すべての権利を保有します。 | ![]() |