Generátory
Psát pokaždé coroutine.resume a chytat true vás brzy omrzí. Když chcete jen hodnoty, které korutina předává přes yield, použijte coroutine.wrap. Také vytvoří korutinu, ale místo ní vám vrátí funkci: každé zavolání té funkce korutinu spustí a vrátí jen hodnoty z yield, bez true:
-- Emin pytlík se semínky
local dalsiSemeno = coroutine.wrap(function()
coroutine.yield("mrkev")
coroutine.yield("brambory")
coroutine.yield("dýně")
end)
print(dalsiSemeno())
print(dalsiSemeno())
print("Poslední: " .. dalsiSemeno())Vypíše:
mrkev
brambory
Poslední: dýněFunkce pro korutinu je tu anonymní, zapsaná rovnou v závorkách, jak to znáte z lekce o funkcích. Funkci, která vám při každém zavolání dá další hodnotu, se říká generátor.
Generátory v cyklu for. Jeden už jste použili: for slovo in text:gmatch("%a+") do z lekce o řetězcích. gmatch vrací funkci a for … in ji volá před každým průchodem cyklem. Co vrátí, jde do proměnných cyklu; když vrátí nil nebo nic, cyklus skončí. Generátor z coroutine.wrap se sem hodí přesně: když jeho funkce doběhne na konec, volání nevrátí nic a cyklus skončí.
Obvykle napíšete funkci, která dostane nějaké nastavení a vrátí nový generátor. Tenhle projde záhony pole, řádek po řádku:
-- Všechny záhony pole
local function zahony(radky, sloupce)
return coroutine.wrap(function()
for radek = 1, radky do
for sloupec = 1, sloupce do
coroutine.yield(radek, sloupec)
end
end
end)
end
for radek, sloupec in zahony(2, 2) do
print("Záhon " .. radek .. "-" .. sloupec)
endVypíše:
Záhon 1-1
Záhon 1-2
Záhon 2-1
Záhon 2-2Vnořené cykly jsou schované v generátoru a cyklus, který ho používá, je stejně jednoduchý jako cyklus s ipairs. Mezi voláními si korutina pamatuje, kde v obou cyklech je. Každé zavolání zahony(2, 2) vytvoří nový generátor, který začne zase od záhonu 1-1.
Pozor na tohle:
- Generátor se spotřebuje, jakmile jeho funkce skončí. Další zavolání ukončí program chybou
cannot resume dead coroutine. Pro další kolo vytvořte nový generátor. - Obyčejná funkce s
yielduvnitř, kterou nevytvořilocoroutine.wrap, v cyklufornefunguje: cyklus ji spustí jako obyčejnou funkci a jejíyieldselže chybouattempt to yield from outside a coroutine. - Korutina z
coroutine.createnení funkce, takže v cyklufortaké nefunguje:attempt to call a thread value. Proforpoužijtewrap.
Jak psát:
Pokyny
Funkce najdiZrale předává přes yield plodinu každého záhonu, který už rostl dost dlouho. Udělejte z ní generátor, local dalsiZrala = coroutine.wrap(najdiZrale), dvakrát ho zavolejte a vypište, co vrátí. Program vypíše:
mrkev
pšeniceTeď skliďte celé pole. Projděte cyklem nový generátor, for plodina in coroutine.wrap(najdiZrale) do, a pro každý zralý záhon vypište Sklizeň: a jeho plodinu. (Proč nový? dalsiZrala už dvě plodiny vydal a pokračoval by třetí.) Program vypíše:
mrkev
pšenice
Sklizeň: mrkev
Sklizeň: pšenice
Sklizeň: jahodyZačněte programovat zdarma
3/6