Operatoren
Objekte können auch mit Operatoren arbeiten. Normalerweise fragt == zwischen zwei Tabellen, ob es dieselbe Tabelle ist (wie du in der Lektion über Tabellen als Dictionaries gesehen hast, ist {} == {} gleich false), und < oder + zwischen Tabellen endet mit einem Fehler. Mit Metamethoden entscheidest du, was diese Operatoren mit deinen Objekten tun. Hier ist eine Klasse für Säcke mit geernteten Pflanzen:
local Sack = {}
Sack.__index = Sack
function Sack.new(pflanze, kg)
local sack = {pflanze = pflanze, kg = kg}
setmetatable(sack, Sack)
return sack
end
function Sack:__tostring()
return self.pflanze .. ": " .. self.kg .. " kg"
end
function Sack.__add(a, b)
return Sack.new(a.pflanze, a.kg + b.kg)
end
function Sack.__eq(a, b)
return a.pflanze == b.pflanze and a.kg == b.kg
end
function Sack.__lt(a, b)
return a.kg < b.kg
end
local kartoffeln = Sack.new("Kartoffel", 20)
local mehrKartoffeln = Sack.new("Kartoffel", 15)
local karotten = Sack.new("Karotte", 20)
print(kartoffeln + mehrKartoffeln)
print(kartoffeln == karotten, kartoffeln == Sack.new("Kartoffel", 20))
print(mehrKartoffeln < kartoffeln, mehrKartoffeln > kartoffeln)
local saecke = {Sack.new("Kürbis", 40), karotten, mehrKartoffeln}
table.sort(saecke)
for _, sack in ipairs(saecke) do
print(sack)
endDas gibt Folgendes aus:
Kartoffel: 35 kg
false true
true false
Kartoffel: 15 kg
Karotte: 20 kg
Kürbis: 40 kgDie Metamethode eines Operators bekommt beide Seiten, a von links und b von rechts, und das Ergebnis des Operators ist, was sie zurückgibt. Deshalb werden diese Metamethoden mit einem Punkt und zwei Parametern definiert: Beide Seiten sind gleichberechtigt. (function Sack:__lt(other), mit self links und other rechts, wäre dieselbe Funktion.)
__addist+.kartoffeln + mehrKartoffelnruftSack.__add(kartoffeln, mehrKartoffeln)auf, was einen neuen Sack mit 35 kg zurückgibt; keiner der beiden Säcke ändert sich. Die anderen funktionieren genauso:__subfür-,__mulfür*,__divfür/.__eqist==(und~=, sein Gegenteil). Hier sind zwei Säcke gleich, wenn sie dieselbe Pflanze enthalten und gleich viel wiegen, auch wenn es verschiedene Tabellen sind. Lua ruft__eqnur auf, wenn beide Seiten Tabellen sind; ein Sack, der mit einer Zahl verglichen wird, ist einfach nicht gleich.__ltist<(less than, kleiner als).a > bist dasselbe wieb < a, also benutzt auch>__lt.<=und>=brauchen eine eigene Metamethode,__le; ohne sie enden sie mitattempt to compare two table values.table.sortvergleicht Einträge mit<. Mit__ltsortiert es die Säcke ohne Vergleichsfunktion, den leichtesten zuerst. Ohne__ltendettable.sort(saecke)mitattempt to compare two table values, diesmal ohnemain.lua:und Zeilennummer davor, weil der Fehler intable.sortpassiert. Die Zeile, die es aufgerufen hat, findest du im Traceback unter der Meldung.
Typischer Fehler: einen Operator mit etwas zu benutzen, das kein Objekt ist. kartoffeln + 5 ruft Sack.__add(kartoffeln, 5) auf, und b.kg auf der Zahl 5 endet mit attempt to index a number value (local 'b').
So schreibst du es:
Anweisungen
- 1
Führe das Programm aus:
table.sortweiß nicht, wie es Pflanzen vergleichen soll. FügePflanzeein__lthinzu, sodass die billigere Pflanze zuerst kommt. Das Programm gibt aus:Karotte: 5 Münzen Kartoffel: 8 Münzen Erdbeere: 12 Münzen Kürbis: 20 Münzen - 2
Füge
__eqhinzu: Zwei Pflanzen sind gleich, wenn sie denselben Namen und denselben Preis haben. Gib am Ende des Programms aus, obpflanzen[1]gleich einer neuen PflanzePflanze.new("Karotte", 5)ist, und in der nächsten Zeile, obpflanzen[2]gleichPflanze.new("Kartoffel", 10)ist:true false - 3
Hugo verkauft Pflanzen auch im Bündel. Füge
__addhinzu, das aus zwei Pflanzen eine neue macht: Ihr Name sind beide Namen, verbunden mit+, und ihr Preis ist die Summe beider Preise. Gib am Endepflanzen[1] + pflanzen[2]aus und dannpflanzen[1] + pflanzen[2] + pflanzen[3]. Das zweite funktioniert, weil auchpflanzen[1] + pflanzen[2]eine Pflanze ist:Karotte + Kartoffel: 13 Münzen Karotte + Kartoffel + Erdbeere: 25 Münzen