Fehler in Koroutinen
Was passiert, wenn in einer Koroutine etwas schiefgeht? Am zweiten Tag gerät Hugos Route in Schwierigkeiten:
-- Hugo verliert seine Karte
local hugo = coroutine.create(function()
coroutine.yield("Markt")
error("Hugo hat seine Karte verloren")
coroutine.yield("Hof")
end)
print(coroutine.resume(hugo))
print(coroutine.resume(hugo))
print(coroutine.status(hugo))
print(coroutine.resume(hugo))
print("Der Tag geht weiter.")Das gibt Folgendes aus:
true Markt
false main.lua:4: Hugo hat seine Karte verloren
dead
false cannot resume dead coroutine
Der Tag geht weiter.Ein Fehler in einer Koroutine stoppt nicht das Programm, nur die Koroutine. Sie ist von da an dead (zum Hof kommt sie nie), und resume gibt false und die Fehlermeldung zurück, genau wie pcall. Auch eine tote Koroutine fortzusetzen ist kein Fehler: Du bekommst false und cannot resume dead coroutine.
Das ist praktisch, denn eine kaputte Figur stoppt nicht das ganze Spiel. Es ist aber auch eine Falle: Wenn du nicht ansiehst, was resume zurückgibt, verschwindet der Fehler spurlos, und die Koroutine hört einfach stillschweigend auf, etwas zu tun. Wenn also in einer Koroutine etwas nicht passiert, gib aus, was resume zurückgibt. Prüfe in einem fertigen Programm den ersten Wert: Nach local ok, meldung = coroutine.resume(hugo) ist ok gleich false, wenn etwas schiefgegangen ist, und meldung sagt, was.
Ein Generator ist anders. Eine Funktion aus coroutine.wrap gibt kein true oder false zurück, sie reicht den Fehler also weiter, und das Programm stoppt, wie bei jedem anderen Fehler:
-- Hugo verliert schon wieder seine Karte
local naechsterHalt = coroutine.wrap(function()
coroutine.yield("Markt")
error("Hugo hat seine Karte verloren")
end)
print(naechsterHalt())
print(naechsterHalt())
print("Diese Zeile läuft nie.")Das gibt Folgendes aus:
Markt
main.lua:8: main.lua:4: Hugo hat seine Karte verlorenDie Meldung hat zwei Zeilennummern: main.lua:8: ist die Stelle, an der der Generator aufgerufen wurde, und main.lua:4: die, an der der Fehler in ihm passiert ist. Ein verbrauchter Generator stoppt das Programm genauso, mit cannot resume dead coroutine. Wenn du einen Fehler aus einem Generator abfangen musst, rufe ihn mit pcall auf, wie jede andere Funktion: local ok, halt = pcall(naechsterHalt).
Einen weiteren Fehler kennst du schon aus dieser Lektion: coroutine.yield() außerhalb einer Koroutine, zum Beispiel in einer Funktion, die du direkt aufgerufen hast, endet mit attempt to yield from outside a coroutine.
So schreibst du es:
Anweisungen
- 1
Hugo kauft jeden Tag einen Kürbis für 20 Münzen. Führe das Programm aus: Tag 3 und 4 geben Unsinn aus, weil
muenzenan diesen Tagen eine Fehlermeldung enthält und keine Zahl. (error(…, 0)lässt die Zeilennummer weg, wie du aus der Lektion über Funktionen weißt.) Prüfeok: Ist esfalse, gib stattdessen den Tag und die Meldung aus, etwaTag 3: Hugo hat nur noch 10 Münzen übrig. Das Programm gibt aus:Tag 1: Hugo hat 30 Münzen Tag 2: Hugo hat 10 Münzen Tag 3: Hugo hat nur noch 10 Münzen übrig Tag 4: cannot resume dead coroutine - 2
Eine tote Koroutine fortzusetzen ergibt keinen Sinn. Prüfe zu Beginn jedes Tages Hugos Status: Ist er
dead, gib den Tag undHugo ist nach Hause gegangen.aus, statt ihn fortzusetzen. Das Programm gibt aus:Tag 1: Hugo hat 30 Münzen Tag 2: Hugo hat 10 Münzen Tag 3: Hugo hat nur noch 10 Münzen übrig Tag 4: Hugo ist nach Hause gegangen.