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: Plodina je třída, psenice a mrkev jsou plodiny.
  • Plodina.__index = Plodina je ten trik. Plodina bude metatabulkou každé plodiny a její __index je Plodina sama. Když tedy plodině nějaký klíč chybí, hledá ho Lua v tabulce Plodina, kde jsou metody.
  • Plodina.new je konstruktor. Vytvoří tabulku s vlastními daty plodiny, nastaví jí tabulku Plodina jako 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é self nemá.
  • 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')).

Pokyny

Spusťte program: skončí chybou attempt to call a nil value (method 'snes'). Opravte třídu tak, aby program vypsal:

Zlatka: 2 vejce

Př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 vajec

Začněte programovat zdarma

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

Nebo se registrujte pomocí:

5/9