Pozastavení funkce
Vítejte v lekci o korutinách, poslední velké části jazyka Lua. Mnoho začátečníků se s ničím podobným ještě nesetkalo, a proto nezačneme kódem, ale nápadem.
Každá funkce, kterou jste zatím napsali, proběhne od začátku do konce najednou: když ji zavoláte, zbytek programu čeká, dokud neskončí. Teď si představte, že vám Ema vypráví o svém dni kousek po kousku. Ráno řekne: „Nakrmila jsem slepice.“ Pak jde po své práci. Když ji potkáte v poledne, nezačne znovu od začátku, ale pokračuje: „Zalila jsem mrkev.“ Pamatuje si, kde přestala.
Korutina je funkce, která umí totéž: zastavit se uprostřed, zapamatovat si, kde byla (i hodnoty svých lokálních proměnných), a později pokračovat přesně od toho místa. Název pochází z anglického coroutine: „routine“ je staré slovo pro funkci a předpona „co-“ znamená „spolu“, protože korutina se střídá se zbytkem programu. Takhle vypadá Emin den jako korutina:
-- Emin den krok za krokem
local function eminDen()
print("Ema krmí slepice.")
coroutine.yield()
print("Ema zalévá mrkev.")
coroutine.yield()
print("Ema prodává vejce na trhu.")
end
local den = coroutine.create(eminDen)
print(coroutine.status(den))
coroutine.resume(den)
print("(Slunce stoupá výš.)")
coroutine.resume(den)
print(coroutine.status(den))
coroutine.resume(den)
print(coroutine.status(den))Vypíše:
suspended
Ema krmí slepice.
(Slunce stoupá výš.)
Ema zalévá mrkev.
suspended
Ema prodává vejce na trhu.
deadPráci obstarají tři funkce z knihovny coroutine:
coroutine.create(eminDen)vytvoří z funkceeminDenkorutinu. Zatím z ní nic nespustí. Předáváte samotnou funkci, bez závorek.coroutine.resume(den)spustí korutinu a nechá ji běžet, dokud nedojde kecoroutine.yield()nebo na konec funkce. Prvníresumezačne na začátku funkce, každé další pokračuje hned za tímyield, kde se korutina zastavila. (Resume znamená „pokračovat“.)coroutine.yield()uvnitř funkce korutinu pozastaví a program pokračuje za tímresume, které ji spustilo. (Yield znamená „dát přednost“, jako auto na křižovatce.)
coroutine.status(den) řekne, v jakém stavu korutina je: suspended (pozastavená: ještě nezačala, nebo čeká u yield), running (její kód právě běží, takže tohle může zjistit jen korutina sama o sobě) nebo dead (doběhla na konec své funkce a už pokračovat nemůže; doslova „mrtvá“).
K čemu to je? Hry jsou plné věcí, které chvíli trvají: obchodník Hugo cestuje od města k městu, dveře se pomalu otevírají, Ema přechází přes pole. Hra kreslí nový obrázek (snímek, anglicky frame) mnohokrát za sekundu, nebo v tahové hře dává tah každé postavě, a všechny tyhle věci musí postupovat po malých krocích. S korutinou napíšete takovou věc jako jednu obyčejnou funkci od začátku do konce a coroutine.yield() dáte všude, kde má počkat na další snímek nebo tah. Takové scénáře budete psát později v této lekci.
Časté chyby:
- Zavolat funkci sami,
eminDen(), nebo se závorkami vcoroutine.create(eminDen()). V obou případech poběžíeminDenjako obyčejná funkce, ne jako korutina, a jejíyieldnemá co pozastavit. Program vypíšeEma krmí slepice.a skončí chybouattempt to yield from outside a coroutine(„pokus o yield mimo korutinu“). Tahle hláška nemá číslo řádku; řádek najdete vestack traceback:pod ní. - Zavolat korutinu jako funkci,
den(). Korutina není funkce, je to hodnota vlastního typuthread, a proto dostaneteattempt to call a thread value (local 'den'). Korutina se spouští jen přescoroutine.resume.
Jak psát:
Pokyny
Ema zalévá pole, ale po prvním záhonu si chce odpočinout. Udělejte z funkce zalijPole korutinu: za zalití záhonu 1 a za zalití záhonu 2 (za záhon 3 už ne) dejte coroutine.yield(). Volání zalijPole() nahraďte řádkem local zalevani = coroutine.create(zalijPole), korutinu zalevani jednou spusťte pomocí resume a pak vypište Ema si dává přestávku. Program vypíše:
Záhon 1 je zalitý
Ema si dává přestávku.Po přestávce vypište stav korutiny za textem Stav: . Pak korutinu zalevani ještě dvakrát spusťte pomocí resume a vypište její stav znovu. Program vypíše:
Záhon 1 je zalitý
Ema si dává přestávku.
Stav: suspended
Záhon 2 je zalitý
Záhon 3 je zalitý
Stav: deadZačněte programovat zdarma
1/6