Operátory

I s operátory můžou objekty pracovat. Normálně se == mezi dvěma tabulkami ptá, jestli jde o tutéž tabulku (jak jste viděli v lekci o tabulkách jako slovnících, {} == {} je false), a < nebo + mezi tabulkami skončí chybou. Metametody vám dovolí určit, co mají tyto operátory s vašimi objekty dělat. Tady je třída pro pytle se sklizenou úrodou:

local Pytel = {}
Pytel.__index = Pytel

function Pytel.new(plodina, kg)
    local pytel = {plodina = plodina, kg = kg}
    setmetatable(pytel, Pytel)
    return pytel
end

function Pytel:__tostring()
    return self.plodina .. ": " .. self.kg .. " kg"
end

function Pytel.__add(a, b)
    return Pytel.new(a.plodina, a.kg + b.kg)
end

function Pytel.__eq(a, b)
    return a.plodina == b.plodina and a.kg == b.kg
end

function Pytel.__lt(a, b)
    return a.kg < b.kg
end

local brambory = Pytel.new("Brambory", 20)
local dalsiBrambory = Pytel.new("Brambory", 15)
local mrkev = Pytel.new("Mrkev", 20)

print(brambory + dalsiBrambory)
print(brambory == mrkev, brambory == Pytel.new("Brambory", 20))
print(dalsiBrambory < brambory, dalsiBrambory > brambory)

local pytle = {Pytel.new("Dýně", 40), mrkev, dalsiBrambory}
table.sort(pytle)
for _, pytel in ipairs(pytle) do
    print(pytel)
end

Vypíše:

Brambory: 35 kg
false	true
true	false
Brambory: 15 kg
Mrkev: 20 kg
Dýně: 40 kg

Metametoda operátoru dostane obě strany, a zleva a b zprava, a výsledkem operátoru je to, co vrátí. Proto se tyto metametody definují s tečkou a dvěma parametry: obě strany jsou si rovné. (function Pytel:__lt(jiny), se self vlevo a jiny vpravo, by byla tatáž funkce.)

  • __add je +. brambory + dalsiBrambory zavolá Pytel.__add(brambory, dalsiBrambory) a ta vrátí nový pytel s 35 kg; žádný z obou pytlů se nezmění. Stejně fungují __sub pro -, __mul pro * a __div pro /.
  • __eq je == (a také ~=, jeho opak). Tady jsou dva pytle stejné, když je v nich stejná plodina a stejně váží, i když jsou to dvě různé tabulky. Lua zavolá __eq, jen když jsou na obou stranách tabulky; pytel porovnaný s číslem prostě stejný není.
  • __lt je < (z anglického less than, menší než). a > b je totéž co b < a, a tak i > používá __lt. <= a >= potřebují vlastní metametodu __le; bez ní skončí chybou attempt to compare two table values.
  • table.sort porovnává prvky pomocí <. Díky __lt proto seřadí pytle i bez porovnávací funkce, od nejlehčího. Bez __lt by table.sort(pytle) skončilo chybou attempt to compare two table values, tentokrát bez main.lua: a čísla řádku na začátku, protože chyba vznikne uvnitř table.sort. Řádek, který ji zavolal, najdete ve výpisu pod hláškou.

Typická chyba je použít operátor s něčím, co objekt není. brambory + 5 zavolá Pytel.__add(brambory, 5) a b.kg u čísla 5 skončí chybou attempt to index a number value (local 'b').

Pokyny

Spusťte program: table.sort neumí plodiny porovnat. Přidejte třídě Plodina metametodu __lt, aby levnější plodina byla první. Program vypíše:

Mrkev: 5 mincí
Brambory: 8 mincí
Jahody: 12 mincí
Dýně: 20 mincí

Přidejte __eq: dvě plodiny jsou stejné, když mají stejný název i stejnou cenu. Na konci programu vypište, jestli se plodiny[1] rovná nové plodině Plodina.new("Mrkev", 5), a na další řádek, jestli se plodiny[2] rovná Plodina.new("Brambory", 10):

true
false

Hugo prodává plodiny i v balíčcích. Přidejte __add, která ze dvou plodin vyrobí novou: její název budou oba názvy spojené textem + a její cena bude součet obou cen. Na konci vypište plodiny[1] + plodiny[2] a potom plodiny[1] + plodiny[2] + plodiny[3]. Druhé sčítání funguje, protože plodiny[1] + plodiny[2] je zase plodina:

Mrkev + Brambory: 13 mincí
Mrkev + Brambory + Jahody: 25 mincí

Začněte programovat zdarma

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

Nebo se registrujte pomocí:

7/9