Metody a self
V zápisu farma.popis(farma) píšete farma dvakrát: jednou, abyste našli funkci, a podruhé, abyste jí farmu předali. Objekty se takhle používají pořád, a tak má Lua zkratku, dvojtečku:
local farma = {nazev = "Farma Slunečnice", mince = 120}
function farma.popis(f)
print(f.nazev .. ": " .. f.mince .. " mincí")
end
farma:popis()Vypíše:
Farma Slunečnice: 120 mincífarma:popis() je zkratka pro farma.popis(farma): Lua vezme funkci z tabulky a jako první argument jí předá samotnou tabulku. Další argumenty následují za ní: farma:vydelej(30) znamená farma.vydelej(farma, 30).
Dvojtečku můžete použít i při definici funkce. function farma:vydelej(castka) je zkratka pro function farma.vydelej(self, castka): Lua přidá skrytý první parametr jménem self (anglicky „sám“). Když funkci zavoláte s dvojtečkou, je v self tabulka, na které jste ji zavolali:
local mrkev = {nazev = "Mrkev", vek = 0, dny = 3}
function mrkev:dalsiDen()
self.vek = self.vek + 1
end
function mrkev:jeZrala()
return self.vek >= self.dny
end
mrkev:dalsiDen()
mrkev:dalsiDen()
print(mrkev.vek, mrkev:jeZrala())
mrkev:dalsiDen()
print(mrkev.vek, mrkev:jeZrala())Vypíše:
2 false
3 trueVe volání mrkev:dalsiDen() je self mrkev, takže self.vek = self.vek + 1 přidá mrkvi jeden den. Funkci v objektu, která dostává objekt jako self, se říká metoda a mrkev:dalsiDen() je volání metody. Uvnitř metody používejte vždy self, ne název tabulky. Pak bude stejná metoda fungovat pro každou tabulku, na které ji zavoláte, a to budete potřebovat hned v příštím cvičení.
Texty fungují stejně. V lekci o řetězcích jste se dozvěděli, že s:upper() je zkratka pro string.upper(s). Teď už víte, co dělá dvojtečka: s:upper() je s.upper(s), volání metody s textem jako prvním argumentem:
local s = "mrkev"
print(s:upper(), s.upper(s), string.upper(s))Vypíše:
MRKEV MRKEV MRKEVJak text najde funkci upper v tabulce string, uvidíte ve cvičení o metatabulkách.
Klasická chyba: tečka místo dvojtečky. Metodu definovanou s dvojtečkou musíte s dvojtečkou i volat. S tečkou jí Lua tabulku nepředá a self je nil:
local mrkev = {nazev = "Mrkev", vek = 0, dny = 3}
function mrkev:dalsiDen()
self.vek = self.vek + 1
end
mrkev.dalsiDen()Program skončí chybou:
main.lua:4: attempt to index a nil value (local 'self')
stack traceback:
main.lua:4: in field 'dalsiDen'
main.lua:7: in main chunkPrvní řádek ukazuje na řádek 4 uvnitř metody, kde se self používá. Chyba je ale v řádku, který metodu zavolal, a ten najdete na konci výpisu: main.lua:7. Údaj in field 'dalsiDen' prozrazuje, že funkce byla zavolána s tečkou; při volání s dvojtečkou by tam stálo in method 'dalsiDen'. Kdykoli chybová hláška zmiňuje (local 'self'), hledejte tečku, která má být dvojtečkou.
Opačná chyba je funkce definovaná s tečkou, function mrkev.dalsiDen(dny), a zavolaná s dvojtečkou, mrkev:dalsiDen(2). Dvojtečka předá jako první argument tabulku, takže v dny bude mrkev a dvojka se zahodí. Pravidlo je jednoduché: metody definujte s dvojtečkou a volejte je s dvojtečkou.
Jak psát:
Pokyny
Udělejte z obou funkcí metody: definujte je s dvojtečkou, function stodola:vypis() a function stodola:pridejVejce(pocet), uvnitř používejte self a volejte je s dvojtečkou. Program vypíše totéž co předtím.
Přidejte metodu stodola:prodejVejce(pocet), která ze stodoly odebere pocet vajec a vrátí, kolik za ně Ema dostane mincí: 2 mince za vejce. Na konci programu prodejte 10 vajec, vypište utržené mince a znovu obsah stodoly:
Stodola: 12 vajec, 4 litry mléka
Stodola: 18 vajec, 4 litry mléka
Prodáno 10 vajec za 20 mincí
Stodola: 8 vajec, 4 litry mlékaZačněte programovat zdarma
2/9