Klassen
In der vorigen Übung brauchten die Pflanzen zwei Tabellen: pflanzenMethoden mit den Methoden und eine Metatabelle {__index = pflanzenMethoden}, für jede Pflanze eine neue. Lua-Programmierer lassen meistens eine Tabelle beide Aufgaben übernehmen: Sie enthält die Methoden, sie ist die Metatabelle jeder Pflanze, und ihr __index zeigt auf sie selbst. Eine solche Tabelle heißt Klasse:
local Pflanze = {}
Pflanze.__index = Pflanze
function Pflanze.new(name, tage)
local pflanze = {name = name, tage = tage, alter = 0}
setmetatable(pflanze, Pflanze)
return pflanze
end
function Pflanze:wachsen()
self.alter = self.alter + 1
end
function Pflanze:istReif()
return self.alter >= self.tage
end
local weizen = Pflanze.new("Weizen", 2)
local karotte = Pflanze.new("Karotte", 3)
weizen:wachsen()
weizen:wachsen()
karotte:wachsen()
print(weizen.name, weizen:istReif())
print(karotte.name, karotte:istReif())Das gibt Folgendes aus:
Weizen true
Karotte falseZeile für Zeile:
local Pflanze = {}erzeugt die Klasse, eine gewöhnliche Tabelle. Klassennamen beginnen mit einem Großbuchstaben:Pflanzeist die Klasse,weizenundkarottesind Pflanzen.Pflanze.__index = Pflanzeist der Trick.Pflanzewird die Metatabelle jeder Pflanze, und ihr__indexistPflanzeselbst. Fehlt einer Pflanze also ein Schlüssel, sucht Lua ihn inPflanze, wo die Methoden stehen.Pflanze.newist der Konstruktor. Er erzeugt eine Tabelle mit den eigenen Daten der Pflanze, setztPflanzeals ihre Metatabelle und gibt sie zurück.newist in Lua der übliche Name für einen Konstruktor. Rufe ihn mit einem Punkt auf,Pflanze.new("Weizen", 2): Du rufst ihn auf der Klasse auf, bevor es irgendeine Pflanze gibt, also gibt es keinself.function Pflanze:wachsen()definiert eine Methode der Klasse mit einem Doppelpunkt, und die Pflanzen rufen sie mit einem Doppelpunkt auf:weizen:wachsen().
Ein Objekt, das von einer Klasse erzeugt wurde, heißt Instanz dieser Klasse: weizen und karotte sind Instanzen von Pflanze. Jede enthält nur ihre eigenen Daten; die Methoden stehen einmal in Pflanze. Anders als viele andere Sprachen hat Lua kein besonderes Schlüsselwort für Klassen. Eine Klasse ist dieses Muster aus einer Tabelle, __index und einem Konstruktor, und du findest es in fast jedem größeren Lua-Programm.
setmetatable gibt die Tabelle zurück, die es bekommt, deshalb siehst du oft einen kürzeren Konstruktor: local pflanze = setmetatable({name = name, tage = tage, alter = 0}, Pflanze). Er tut dasselbe.
Der klassische Fehler: Pflanze.__index = Pflanze vergessen. Ohne diese Zeile sieht alles gut aus, bis du eine Methode aufrufst:
local Pflanze = {}
function Pflanze.new(name, tage)
local pflanze = {name = name, tage = tage, alter = 0}
setmetatable(pflanze, Pflanze)
return pflanze
end
function Pflanze:wachsen()
self.alter = self.alter + 1
end
local weizen = Pflanze.new("Weizen", 2)
weizen:wachsen()Das Programm endet mit einem Fehler:
main.lua:14: attempt to call a nil value (method 'wachsen')Pflanze ist die Metatabelle des Weizens, aber ohne __index weiß Lua nicht, dass es fehlende Schlüssel dort suchen soll. Also ist weizen.wachsen gleich nil, und nil aufzurufen ist ein Fehler. (method 'wachsen') bedeutet, dass eine Methode nicht gefunden wurde: Prüfe __index und den Namen der Methode auf Tippfehler.
Die Fehler aus den vorigen Übungen können hier auch passieren. Ohne return pflanze gibt Pflanze.new nil zurück (attempt to index a nil value (local 'weizen')), und weizen.wachsen() mit einem Punkt lässt self leer (attempt to index a nil value (local 'self')).
So schreibst du es:
Anweisungen
- 1
Führe das Programm aus: Es endet mit
attempt to call a nil value (method 'legen'). Repariere die Klasse, sodass das Programm Folgendes ausgibt:Goldi: 2 Eier - 2
Füge eine Methode
Huhn:ausgeben()hinzu, die die Zeile über das Huhn so ausgibt, wie es jetzt die letzte Zeile des Programms tut. Ersetze dann diese letzte Zeile durchgoldi:ausgeben(). Das Programm gibt dasselbe aus. - 3
Erzeuge mit
Huhn.newzwei weitere Hühner: Perle, die 3 Eier legt, und Rosi, die 4 legt. Gib ihre Berichte unter Goldis aus und dann die Zahl der Eier aller drei Hühner zusammen:Goldi: 2 Eier Perle: 3 Eier Rosi: 4 Eier Gesamt: 9 Eier