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)
end

Vypíše:

Záhon 1-1
Záhon 1-2
Záhon 2-1
Záhon 2-2

Vnoř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 yield uvnitř, kterou nevytvořilo coroutine.wrap, v cyklu for nefunguje: cyklus ji spustí jako obyčejnou funkci a její yield selže chybou attempt to yield from outside a coroutine.
  • Korutina z coroutine.create není funkce, takže v cyklu for také nefunguje: attempt to call a thread value. Pro for použijte wrap.

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šenice

Teď 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ň: jahody

Začněte programovat zdarma

Registrací souhlasíte s provozními podmínkami a zásadami ochrany osobních údajů.

Nebo se registrujte pomocí:

3/6