この初版はLua 5.0向けに書かれています。後のバージョンでも大部分は関連性がありますが、いくつかの違いがあります。
第4版はLua 5.3を対象としており、Amazonや他の書店で入手できます。
本書を購入することで、Luaプロジェクトの支援にもなります。
![]() |
Luaプログラミング | ![]() |
第一部 言語 第9章 コルーチン |
Luaは、すべてのコルーチン関数をcoroutine
テーブルにまとめて提供しています。create
関数は新しいコルーチンを作成します。この関数は、コルーチンが実行するコードを含む関数を唯一の引数として取ります。戻り値は、新しいコルーチンを表すthread
型の値です。多くの場合、create
への引数は、以下のように無名関数です。
co = coroutine.create(function () print("hi") end) print(co) --> thread: 0x8071d98
コルーチンは、中断、実行中、死亡の3つの状態のいずれかになります。コルーチンを作成すると、中断状態で開始されます。つまり、コルーチンは作成時に自動的に本体を実行しません。status
関数を使用して、コルーチンの状態を確認できます。
print(coroutine.status(co)) --> suspended
coroutine.resume
関数は、コルーチンの実行を(再)開始し、状態を中断から実行中に変更します。coroutine.resume(co) --> hiこの例では、コルーチン本体は単に
"hi"
を出力して終了し、コルーチンを死亡状態のままにします。この状態からは復帰できません。print(coroutine.status(co)) --> dead
これまでのところ、コルーチンは関数を呼び出す複雑な方法のように見えます。コルーチンの真の力は、実行中のコルーチンが実行を中断して後で再開できるようにするyield
関数にあります。簡単な例を見てみましょう。
co = coroutine.create(function () for i=1,10 do print("co", i) coroutine.yield() end end)このコルーチンを再開すると、実行が開始され、最初の
yield
まで実行されます。coroutine.resume(co) --> co 1状態を確認すると、コルーチンが中断されているため、再び再開できることがわかります。
print(coroutine.status(co)) --> suspendedコルーチンの視点から見ると、中断中に発生するすべてのアクティビティは、
yield
の呼び出し内で発生しています。コルーチンを再開すると、このyield
の呼び出しが最終的に戻り、コルーチンは次のyieldまたは終了まで実行を続けます。coroutine.resume(co) --> co 2 coroutine.resume(co) --> co 3 ... coroutine.resume(co) --> co 10 coroutine.resume(co) -- prints nothing最後の
resume
呼び出し中に、コルーチン本体はループを終了して戻ったので、コルーチンは現在死亡しています。もう一度再開しようとすると、resume
はfalseとエラーメッセージを返します。print(coroutine.resume(co)) --> false cannot resume dead coroutine
resume
は保護モードで実行されることに注意してください。そのため、コルーチン内でエラーが発生した場合、Luaはエラーメッセージを表示せず、代わりにresume
呼び出しに返します。Luaの便利な機能は、resume-yieldのペアがそれらの間でデータを交換できることです。対応するyield
を待機していない最初のresume
は、追加の引数をコルーチンメイン関数の引数として渡します。
co = coroutine.create(function (a,b,c) print("co", a,b,c) end) coroutine.resume(co, 1, 2, 3) --> co 1 2 3
resume
の呼び出しは、エラーがないことを示すtrueの後に、対応するyield
に渡された引数を返します。co = coroutine.create(function (a,b) coroutine.yield(a + b, a - b) end) print(coroutine.resume(co, 20, 10)) --> true 30 10対称的に、
yield
は、対応するresume
に渡された追加の引数を返します。co = coroutine.create (function () print("co", coroutine.yield()) end) coroutine.resume(co) coroutine.resume(co, 4, 5) --> co 4 5最後に、コルーチンが終了すると、メイン関数によって返された値は、対応する
resume
に渡されます。co = coroutine.create(function () return 6, 7 end) print(coroutine.resume(co)) --> true 6 7
同じコルーチンですべての機能を使用することはめったにありませんが、すべてに用途があります。
コルーチンについてすでに知っている人のために、先に進む前にいくつかの概念を明確にしておくことが重要です。Luaは、私が*非対称コルーチン*と呼ぶものを提供しています。つまり、コルーチンの実行を中断する関数と、中断されたコルーチンを再開する別の関数があります。他の言語の中には、*対称コルーチン*を提供するものがあり、任意のコルーチンから別のコルーチンに制御を移すための関数は1つだけです。
非対称コルーチンを*セミコルーチン*と呼ぶ人もいます(対称ではないため、実際には*co*ではありません)。ただし、*セミコルーチン*という同じ用語を使用して、コルーチンが補助関数内にない場合、つまり制御スタックに保留中の呼び出しがない場合にのみ実行を中断できる、コルーチンの制限された実装を示す人もいます。言い換えれば、そのようなセミコルーチンのメインボディのみがyieldできます。Pythonの*ジェネレーター*は、この意味でのセミコルーチンの例です。
対称コルーチンと非対称コルーチンの違いとは異なり、コルーチンとジェネレーター(Pythonで提示されているように)の違いは根本的なものです。ジェネレーターは、真のコルーチンで記述できるいくつかの興味深い構成を実装するのに十分強力ではありません。Luaは、真の非対称コルーチンを提供します。対称コルーチンを好む人は、Luaの非対称機能の上にそれらを実装できます。それは簡単な作業です。(基本的に、各転送はyieldの後にresumeを実行します。)
Copyright © 2003–2004 Roberto Ierusalimschy. All rights reserved. 著作権 © 2003–2004 Roberto Ierusalimschy. 無断転載を禁じます。 | ![]() |