Třídy
V minulém cvičení potřebovaly plodiny dvě tabulky: metodyPlodiny s metodami a metatabulku {__index = metodyPlodiny}, pro každou plodinu novou. Programátoři v Lua obvykle svěřují obě úlohy jedné tabulce: drží metody, je metatabulkou každé plodiny a její __index ukazuje na ni samotnou. Takové tabulce se říká třída:
local Plodina = {}
Plodina.__index = Plodina
function Plodina.new(nazev, dny)
local plodina = {nazev = nazev, dny = dny, vek = 0}
setmetatable(plodina, Plodina)
return plodina
end
function Plodina:dalsiDen()
self.vek = self.vek + 1
end
function Plodina:jeZrala()
return self.vek >= self.dny
end
local psenice = Plodina.new("Pšenice", 2)
local mrkev = Plodina.new("Mrkev", 3)
psenice:dalsiDen()
psenice:dalsiDen()
mrkev:dalsiDen()
print(psenice.nazev, psenice:jeZrala())
print(mrkev.nazev, mrkev:jeZrala())Vypíše:
Pšenice true
Mrkev falseŘádek po řádku:
local Plodina = {}vytvoří třídu, obyčejnou tabulku. Názvy tříd začínají velkým písmenem:Plodinaje třída,pseniceamrkevjsou plodiny.Plodina.__index = Plodinaje ten trik.Plodinabude metatabulkou každé plodiny a její__indexjePlodinasama. Když tedy plodině nějaký klíč chybí, hledá ho Lua v tabulcePlodina, kde jsou metody.Plodina.newje konstruktor. Vytvoří tabulku s vlastními daty plodiny, nastaví jí tabulkuPlodinajako metatabulku a vrátí ji.new(anglicky „nový“) je v Lua obvyklý název konstruktoru, i v programech psaných česky. Volá se s tečkou,Plodina.new("Pšenice", 2): voláte ho na třídě, dřív než nějaká plodina existuje, takže žádnéselfnemá.function Plodina:dalsiDen()definuje metodu třídy s dvojtečkou a plodiny ji s dvojtečkou volají:psenice:dalsiDen().
Objektu vytvořenému třídou se říká instance té třídy: psenice a mrkev jsou instance třídy Plodina. Každá drží jen svá data, metody jsou jednou, v tabulce Plodina. Na rozdíl od mnoha jiných jazyků nemá Lua pro třídy zvláštní klíčové slovo. Třída je tenhle vzor z tabulky, __index a konstruktoru a najdete ho skoro v každém větším programu v Lua.
setmetatable vrací tabulku, kterou dostala, a tak často uvidíte kratší konstruktor: local plodina = setmetatable({nazev = nazev, dny = dny, vek = 0}, Plodina). Dělá totéž.
Klasická chyba: zapomenuté Plodina.__index = Plodina. Bez tohoto řádku vypadá všechno v pořádku, dokud nezavoláte metodu:
local Plodina = {}
function Plodina.new(nazev, dny)
local plodina = {nazev = nazev, dny = dny, vek = 0}
setmetatable(plodina, Plodina)
return plodina
end
function Plodina:dalsiDen()
self.vek = self.vek + 1
end
local psenice = Plodina.new("Pšenice", 2)
psenice:dalsiDen()Program skončí chybou:
main.lua:14: attempt to call a nil value (method 'dalsiDen')Plodina je sice metatabulkou pšenice, ale bez __index Lua neví, že v ní má hledat chybějící klíče. psenice.dalsiDen je proto nil a zavolat nil nejde. (method 'dalsiDen') znamená, že se metoda nenašla: zkontrolujte __index a také překlepy v názvu metody.
Stát se tu můžou i chyby z minulých cvičení. Bez return plodina vrátí Plodina.new hodnotu nil (attempt to index a nil value (local 'psenice')) a psenice.dalsiDen() s tečkou nechá self prázdné (attempt to index a nil value (local 'self')).
Jak psát:
Pokyny
Spusťte program: skončí chybou attempt to call a nil value (method 'snes'). Opravte třídu tak, aby program vypsal:
Zlatka: 2 vejcePřidejte metodu Slepice:vypis(), která vypíše řádek o slepici stejně jako teď poslední řádek programu. Ten řádek pak nahraďte voláním zlatka:vypis(). Program vypíše totéž.
Pomocí Slepice.new vytvořte další dvě slepice: Perlu, která snese 3 vejce, a Kropenku, která snese 4. Jejich výpisy dejte pod Zlatčin a nakonec vypište, kolik vajec mají všechny tři slepice dohromady:
Zlatka: 2 vejce
Perla: 3 vejce
Kropenka: 4 vejce
Celkem: 9 vajecZačněte programovat zdarma
5/9