Konstruktory

Mrkev z minulého cvičení je jedna tabulka, napsaná ručně. Na farmě ale roste plodin mnoho: mrkev, brambory, dýně… Kdybyste každou z nich psali celou i s metodami, opakovali byste pořád stejný kód. Místo toho napište funkci, která je vyrábí. Funkci, která vytvoří nový objekt a vrátí ho, se říká konstruktor:

local function novaPlodina(nazev, dny)
    local plodina = {nazev = nazev, dny = dny, vek = 0}

    function plodina:dalsiDen()
        self.vek = self.vek + 1
    end

    function plodina:popis()
        print(self.nazev .. ": den " .. self.vek .. "/" .. self.dny)
    end

    return plodina
end

local mrkev = novaPlodina("Mrkev", 3)
local dyne = novaPlodina("Dýně", 7)
mrkev:dalsiDen()
mrkev:dalsiDen()
dyne:dalsiDen()
mrkev:popis()
dyne:popis()

Vypíše:

Mrkev: den 2/3
Dýně: den 1/7

Každé volání novaPlodina spustí její kód znovu: vytvoří novou tabulku, vloží do ní obě metody a vrátí ji. mrkev a dyne jsou dvě samostatné tabulky, takže když mrkev povyroste, dýně se nezmění. A protože metody používají self, a ne pevný název, funguje stejný kód pro obě.

V zápisu {nazev = nazev, dny = dny, vek = 0} je stejné slovo dvakrát, což je u konstruktorů běžné. Vlevo od = je klíč, vpravo hodnota, tady parametr stejného jména. novaPlodina("Mrkev", 3) tedy vytvoří {nazev = "Mrkev", dny = 3, vek = 0}.

Klasická chyba: zapomenutý return. Bez return plodina konstruktor tabulku sice vytvoří, ale nevrátí ji, a proměnná dostane nil:

local function novaPlodina(nazev, dny)
    local plodina = {nazev = nazev, dny = dny, vek = 0}

    function plodina:dalsiDen()
        self.vek = self.vek + 1
    end
end

local mrkev = novaPlodina("Mrkev", 3)
mrkev:dalsiDen()

Program skončí chybou:

main.lua:10: attempt to index a nil value (local 'mrkev')

Chyba ukazuje na řádek, kde objekt poprvé použijete, ne na konstruktor. Když je nový objekt nil, zkontrolujte return v konstruktoru.

Jeden problém. Každé volání novaPlodina vytvoří znovu i metody: řádky s function plodina:dalsiDen() se provedou znovu a vyrobí novou funkci. dalsiDen mrkve a dalsiDen dýně dělají totéž, ale jsou to dvě různé funkce:

local function novaPlodina(nazev)
    local plodina = {nazev = nazev, vek = 0}

    function plodina:dalsiDen()
        self.vek = self.vek + 1
    end

    return plodina
end

local mrkev = novaPlodina("Mrkev")
local dyne = novaPlodina("Dýně")
print(mrkev.dalsiDen == dyne.dalsiDen)

Vypíše:

false

U tří plodin na tom nesejde. Ale pole s 1 000 plodinami a deseti metodami by obsahovalo 10 000 funkcí, které jsou kopiemi pořád stejných deseti. Lepší by bylo mít metody na jednom místě, společné pro všechny plodiny, a v každé plodině jen její vlastní data: název, dny a stáří. K tomu slouží metatabulky, o kterých je příští cvičení.

Pokyny

Ema nemá jen Zlatku. Udělejte z kódu, který Zlatku vytváří, konstruktor: lokální funkci novaSlepice(jmeno), která vytvoří slepici se jménem jmeno a 0 vejci, dá jí obě metody a vrátí ji. Zlatku pak vytvořte pomocí local zlatka = novaSlepice("Zlatka"). Program vypíše totéž co předtím.

Pod Zlatkou vytvořte pomocí novaSlepice druhou slepici, Perlu. Perla snese 3 vejce a potom ještě 1. Její výpis dejte pod Zlatčin:

Zlatka snesla 2 vejce
Perla snesla 4 vejce

Ověřte si, co cvičení říká o metodách: na konci programu vypište zlatka.snes == perla.snes. Program vypíše:

Zlatka snesla 2 vejce
Perla snesla 4 vejce
false

Začněte programovat zdarma

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

Nebo se registrujte pomocí:

3/9