*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 の展開」を知っておく必要がある。

トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS