Fehler und pcall
Bisher kamen die Fehler von Lua selbst: nil aufrufen, nil addieren … Auch deine eigenen Funktionen können Fehler melden. Bekommt eine Funktion Werte, mit denen sie nichts anfangen kann, ist es besser, mit einer klaren Meldung anzuhalten, als mit einem falschen Ergebnis weiterzumachen. Dafür gibt es error:
local muenzen = 20
local function kaufeSamen(preis, beutel)
local kosten = preis * beutel
if kosten > muenzen then
error("Nicht genug Münzen")
end
muenzen = muenzen - kosten
return muenzen
end
print(kaufeSamen(2, 5))
print(kaufeSamen(5, 4))
print("Fertig")Das gibt Folgendes aus:
10
main.lua:6: Nicht genug Münzen
stack traceback:
[C]: in function 'error'
main.lua:6: in local 'kaufeSamen'
main.lua:13: in main chunkerror hält das Programm an, genau wie ein Fehler von Lua: Fertig wird nie ausgegeben. Lua setzt main.lua:6: vor deine Meldung: die Zeile, in der error aufgerufen wurde. Der Traceback zeigt, wie das Programm dorthin gekommen ist; lies ihn von unten: Das Hauptprogramm hat kaufeSamen in Zeile 13 aufgerufen, und in Zeile 6 hat kaufeSamen error aufgerufen. ([C] bedeutet eine in Lua eingebaute Funktion, die in der Sprache C geschrieben ist.) Willst du die Position nicht in der Meldung haben, übergib 0 als zweites Argument: error("Nicht genug Münzen", 0).
„Wenn das nicht stimmt, halte mit einem Fehler an“ ist eine so häufige Prüfung, dass es eine Abkürzung dafür gibt: assert(bedingung, meldung). Ist die Bedingung wahr, tut assert nichts; ist sie false oder nil, endet das Programm mit der Meldung:
local function pflanzeSamen(pflanze, beete)
assert(beete > 0, "Bepflanze mindestens ein Beet")
print("Pflanze " .. pflanze .. " auf " .. beete .. " Beeten")
end
pflanzeSamen("Karotten", 3)
pflanzeSamen("Weizen", 0)Das gibt Folgendes aus:
Pflanze Karotten auf 3 Beeten
main.lua:2: Bepflanze mindestens ein BeetManchmal soll ein Fehler nicht das ganze Programm beenden. Emma kann sich die Kürbissamen nicht leisten, will aber trotzdem die anderen kaufen. pcall (englisch „protected call“, geschützter Aufruf) ruft eine Funktion auf und fängt ihren Fehler ab. Übergib ihm die Funktion und dann ihre Argumente: pcall(kaufeSamen, 5, 4) ruft kaufeSamen(5, 4) auf. pcall gibt mehrere Werte zurück: Wenn alles gut geht, true und das, was die Funktion zurückgegeben hat; bei einem Fehler false und die Fehlermeldung. In beiden Fällen läuft das Programm weiter:
local muenzen = 20
local function kaufeSamen(preis, beutel)
local kosten = preis * beutel
if kosten > muenzen then
error("Nicht genug Münzen")
end
muenzen = muenzen - kosten
return muenzen
end
print(pcall(kaufeSamen, 2, 5))
local ok, ergebnis = pcall(kaufeSamen, 5, 4)
if ok then
print("Übrige Münzen: " .. ergebnis)
else
print("Fehler: " .. ergebnis)
end
print("Fertig")Das gibt Folgendes aus:
true 10
Fehler: main.lua:6: Nicht genug Münzen
FertigDer übliche Weg ist der zweite: Speichere die Werte in ok und ergebnis und entscheide anhand von ok, was ergebnis ist. Ein typischer Fehler ist pcall(kaufeSamen(5, 4)). Mit den Klammern hinter kaufeSamen ruft Lua die Funktion sofort auf, noch vor pcall, und ihr Fehler wird nicht abgefangen. Wie bei jeder Funktion, die du an eine andere übergibst, übergib die Funktion selbst und ihre Argumente getrennt.
So schreibst du es:
Anweisungen
- 1
Emmas Münzen sinken unter null. Beende
kaufeSamenvor dem Bezahlen miterror("Nicht genug Münzen für " .. pflanze, 0), wennkostengrößer alsmuenzenist. Dann würde der zweite Einkauf das ganze Programm anhalten, also rufe alle drei Einkäufe überpcallauf und gib aus, was es zurückgibt, zum Beispielprint(pcall(kaufeSamen, "Karotte", 2, 5)). Das Programm gibt Folgendes aus:true 10 false Nicht genug Münzen für Kürbis true 6 - 2
Emma kann nicht null Beutel kaufen. Füge am Anfang von
kaufeSameneinassertmit der Bedingungbeutel > 0und der Meldung"Kaufe mindestens einen Beutel"hinzu. Gib dann am Ende des Programmspcall(kaufeSamen, "Mais", 3, 0)aus. Die neue Zeile istfalseund die Meldung mit ihrer Position, zum Beispiel:false main.lua:5: Kaufe mindestens einen Beutel - 3
Schreibe eine Funktion
versucheZuKaufenmit den Parameternpflanze,preisundbeutel. Sie ruftkaufeSamenüberpcallauf und speichert die Ergebnisse inokundergebnis. Klappt der Einkauf, gibt sieGekauft: …, übrige Münzen: …aus; sonst gibt sieKann … nicht kaufen:und die Fehlermeldung aus. Rufe am Ende des ProgrammsversucheZuKaufen("Erdbeere", 4, 1)undversucheZuKaufen("Kartoffel", 3, 2)auf. Das Programm endet mit:Gekauft: Erdbeere, übrige Münzen: 2 Kann Kartoffel nicht kaufen: Nicht genug Münzen für Kartoffel