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
3Krok 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: 2vejce() 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 10prodejMrkev si pamatuje cenu 5 a prodejDyne cenu 20. Každá vrácená funkce má svou vlastní cena, nastavenou jednou, když vznikla.
Jak psát:
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: 20Napiš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
7Začněte programovat zdarma
9/11