Uzávěry

Funkce může vytvořit jinou funkci a vrátit ji, jako každou jinou hodnotu. Nová funkce si pak pamatuje lokální proměnné funkce, která ji vytvořila, i když ta už skončila. Tady je funkce, která vyrábí počítadla:

local function vytvorPocitadlo()
    local pocet = 0
    return function()
        pocet = pocet + 1
        return pocet
    end
end

local pocitejVejce = vytvorPocitadlo()
print(pocitejVejce())
print(pocitejVejce())
print(pocitejVejce())

Vypíše:

1
2
3

Krok za krokem: vytvorPocitadlo() vytvoří lokální proměnnou pocet s hodnotou 0, pak vytvoří anonymní funkci, vrátí ji a skončí. Vrácená funkce se uloží do pocitejVejce. Normálně lokální proměnné funkce po jejím skončení zaniknou, ale pocet ne: vrácená funkce ho používá, a tak ho Lua uchová, dokud ta funkce existuje. Každé volání pocitejVejce() tenhle pocet zvýší a vrátí.

Funkci spolu s proměnnými, které si pamatuje, se říká uzávěr (anglicky closure). Každé volání vytvorPocitadlo vytvoří nový pocet, takže každé počítadlo má svůj vlastní:

local function vytvorPocitadlo()
    local pocet = 0
    return function()
        pocet = pocet + 1
        return pocet
    end
end

local vejce = vytvorPocitadlo()
local mleko = vytvorPocitadlo()
vejce()
vejce()
mleko()
print("Vejce: " .. vejce())
print("Mléko: " .. mleko())

Vypíše:

Vejce: 3
Mléko: 2

vejce() na samostatném řádku zavolá počítadlo a číslo, které vrátí, zahodí. To je v pořádku. Proč prostě nepoužít jednu proměnnou mimo funkci? Pak by ji mohla změnit kterákoli část programu a pro dvě počítadla byste potřebovali dvě proměnné a dvě funkce. V uzávěru je pocet schovaný: dostane se k němu jen samotné počítadlo.

Parametry vnější funkce jsou také její lokální proměnné, takže si je uzávěr pamatuje také:

local function vytvorProdejce(cena)
    return function(pocet)
        return pocet * cena
    end
end

local prodejMrkev = vytvorProdejce(5)
local prodejDyne = vytvorProdejce(20)
print(prodejMrkev(10), prodejDyne(3), prodejMrkev(2))

Vypíše:

50	60	10

prodejMrkev si pamatuje cenu 5 a prodejDyne cenu 20. Každá vrácená funkce má svou vlastní cena, nastavenou jednou, když vznikla.

Pokyny

Napište funkci vytvorPocitadlo s parametrem krok. Vrátí novou funkci, která při každém zavolání přičte krok ke svému vlastnímu počtu (ten začíná na 0) a vrátí nový počet. Pod ni přidejte tento kód:

local vejce = vytvorPocitadlo(6)
local mleko = vytvorPocitadlo(10)
vejce()
vejce()
mleko()
print("Vejce: " .. vejce())
print("Mléko: " .. mleko())

Ema sbírá vejce po půl tuctu a mléko v desetilitrových konvích, takže program vypíše:

Vejce: 18
Mléko: 20

Napište funkci vytvorRozpocet s parametrem mince. Vrátí funkci s parametrem cena: když je cena nejvýš mince, funkce ji od mince odečte, a v každém případě vrátí, kolik mincí zbývá. Ema i děda Josef dostanou každý svůj rozpočet. Na konec přidejte tento kód:

local ema = vytvorRozpocet(20)
local josef = vytvorRozpocet(15)
print(ema(8))
print(josef(4))
print(ema(5))
print(ema(10))

Poslední nákup stojí víc, než Emě zbývá, takže se neuskuteční. Program vypíše:

12
11
7
7

Začněte programovat zdarma

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

Nebo se registrujte pomocí:

9/11