- 追加された行はこの色です。
- 削除された行はこの色です。
*Luaリファレンス 要注意点 ~コルーチン~ [#wf540f3c]
**この項目を見る前に [#u348e12b]
>先に「[[ASSERT、例外処理>lua_reference_watch_out_point_except]]」内にあるpcallの記述を見ておいたほうが、Luaにおける実装指針が理解できるので良い。
**コルーチン [#k1e1a027]
>
コルーチンはpythonのyieldなど、その他の言語でも良く出てくる概念である。~
LUAのコルーチンはそこそこ(というかかなり)強力な非対称コルーチンと言える。~
(非対称コルーチンにしているのは、結局その方がハンドリングが楽だからと思われる)~
>
最近のスクリプト言語では、通常コルーチンは実装されている。~
しかし、その正確なコントロールは最終的には難しくなってしまうため、~
使用には注意を要するし、安易な利用は避けるべきである。~
特にゲームスクリプトでは、使用を禁止する方がトラブルが無くて良い。~
~
あやふやな知識による使用は''発見・除去双方が困難なバグを招く主原因''となりやすい。
~
**コルーチンの作成 [#l931ba2b]
***coroutine.create(func_type) [#jfd914b7]
>
#sh(lua){{
function dofile (filename)
co = coroutine.create( function() print("hi") end )
print(co) --> thread: 000000000033F490
end
}}
~
**コルーチンの状態 [#f7109bff]
>コルーチンは
|''suspended''|''中断''|
|''runnning''|''実行''|
|''dead''|''終了''|
|''norma''l|''通常''|
の4つの状態を持つ。~
~
''createしただけでは、suspededの状態''となっている
**コルーチンの状態取得 [#u492f72a]
***coroutine.status(co) [#p17b6da2]
>該当のコルーチンインスタンスの状態は
#sh(lua){{
co = coroutine.create( function() print("hi") end )
・・・ -- 何かの処理
coroutine.status(co)
}}
でわかる。
**既存のコルーチンの実行 [#vc4ad650]
***coroutine.resume(co) [#tc273227]
>該当のコルーチンを実行するには
#sh(lua){{
co = coroutine.create( function() print("hi") end )
・・・ -- 何かの処理
coroutine.resume(co)
}}
でよい。
**既存のコルーチンの一時停止(あとで続きから再開する場合) [#r1b74dc4]
***coroutine.yield() [#u57814e8]
>該当のコルーチンを一時的に停止して、後で続きから再開するような仕組みを入れるには~
コルーチンの実行対象となる関数内に、次のように「''coroutine.yield()''」を入れる。
#sh(lua){{
co = coroutine.create(
function ()
for i=1, 10 do
print("co", i)
coroutine.yield()
end
end
)
coroutine.resume(co) ---> co 1 (coroutine.yield()まで実行され、suspendedに戻される)
coroutine.resume(co) ---> co 2 (coroutine.yield()まで実行され、suspendedに戻される)
}}
>~
コルーチンが実行に失敗した場合には、~
#sh(lua){{
print(coroutine.resume(co)) ---> false cannot resume dead coroutine というように第1返値にfalse, 第2返値にエラーメッセージとなる。
}}
resumeは''保護モード''で実行される。よってpcallと同様となる。
**コルーチンへと渡す引数 [#c304aaf0]
>coroutineへの引数は、以下のようにそのまま、resumeに第2引数以下として渡す。~
coroutine.yield()への引数がそのまま、resume呼び出しの2番目以降の返り値となる、~
''その次に呼び出す際の第2引数以降は、必要はない。''
#sh(lua){{
co = coroutine.create(
function(a, b)
for i=1, 10 do
print(a,b)
coroutine.yield( a+5,b-5 )
end
return 3,4
end
)
coroutine.resume(co, 1, 2) ---> true, 6, -4
coroutine.resume(co) ---> true, 6, -4
coroutine.resume(co) ---> true, 6, -4
・・・・
coroutine.resume(co) ---> true, 3, 4
coroutine.resume(co) ---> false, cannot resume dead coroutine
}}
**LUAでの、プロデューサ/コンシューマ [#o25f24a2]
>デザインパターンの一種~
メッセージブロックを送信する側の処理と、メッセージブロックを受信して、実際に処理する処理の分離
データの具体的な入力手段と、実際の入力されたデータ処理を疎結合にするのが狙いである。
#sh(lua){{
function recieve (prod)
local status, value = coroutine.resume(prod)
return value
end
function send (x)
coroutine.yield(x)
end
function producer ()
return coroutine.create(function ()
while true do
local x = io.read()
send(x)
end
end )
end
function consumer(prod)
while true do
local x = recieve(prod)
io.write(x, "\n")
end
end
consumer(producer())
}}
**イタレータとコルーチン [#t561f17d]
>2ずつ増えるイタレータ
#sh(lua){{
function itr()
local co = coroutine.create(function ()
local i = 1
while true do
coroutine.yield(i)
i = i + 2
end
end)
return function ()
local state, res = coroutine.resume(co)
return res
end
end
for i in itr() do
print(i)
if i > 10 then break end
end
}}
**イタレータとcoroutine.wrap [#k146f4ff]
>より簡単に書くならば、coroutine.wrapを利用する。
ccoroutine.wrap は functionを渡すと、コルーチンを生成し、''~
''該当コルーチンのresume関数(自体)を返り値として渡す。''~
#sh(lua){{
local itr = coroutine.wrap(function ()
local i = 1
while true do
coroutine.yield(i)
i = i + 2
end
end)
for i in itr do
print(i)
if i > 10 then break end
end
}}
これらのfor .. in の挙動を理解するためには、~
[イタレータ>lua_reference_watch_out_point_iterator]の項目の「for ... in の展開」を知っておく必要がある。
[[イタレータ>lua_reference_watch_out_point_iterator]]の項目の「for ... in の展開」を知っておく必要がある。