Die Programmiersprache Ruby (German Edition)
Block führt die Anweisung
retry
nicht nur den aktuellen Aufruf des Blocks erneut aus; sie sorgt dafür, dass der Block und der Iterator beendet werden, und wertet den Iteratorausdruck dann erneut aus, um die Iteration neu zu starten. Betrachten Sie den folgenden Code:
n = 10
n.times do |x| # n-mal von 0 bis n-1 iterieren
print x # Iterationsnummer ausgeben
if x == 9 # Wenn wir 9 erreicht haben
n -= 1 # n vermindern (beim nächsten Mal wird 9 nicht erreicht!)
retry # Die Iteration neu starten
end
end
Der Code verwendet
retry
, um den Iterator neu zu starten, sorgt aber dafür, eine Endlosschleife zu vermeiden. Beim ersten Aufruf gibt er die Zahlen
0123456789
aus und startet dann neu. Beim zweiten Aufruf gibt er die Zahlen
012345678
aus und startet nicht mehr neu.
Die Magie der
retry
-Anweisung besteht darin, dass sie den Iterator nicht jedes Mal genau auf dieselbe Weise ausprobiert. Sie wertet den Iteratorausdruck komplett neu aus, was bedeutet, dass die Argumente für den Iterator (und sogar das Objekt, für das er aufgerufen wurde) bei jedem neuen Ausprobieren des Iterators andere sein können. Wenn Sie nicht an hochgradig dynamische Sprachen wie Ruby gewöhnt sind, mag Ihnen diese erneute Auswertung alles andere als intuitiv erscheinen.
Die Anweisung
retry
ist nicht auf den Einsatz in Blöcken beschränkt; sie wertet stets nur den am nächsten gelegenen enthaltenden Methodenaufruf erneut aus. Das bedeutet, dass sie (in älteren Versionen als Ruby 1.9) verwendet werden kann, um Iteratoren wie den folgenden zu schreiben, der wie eine
while
-Schleife funktioniert:
# Diese Methode verhält sich wie eine while-Schleife: Wenn x nicht nil
# und nicht false ist, wird der Block aufgerufen, und dann wird versucht,
# die Schleife neu zu starten und die Bedingung erneut zu prüfen. Diese
# Methode ist etwas anders als eine echte while-Schleife:
# Sie können geschweifte Klammern im C-Stil verwenden, um den
# Schleifenrumpf abzugrenzen. Und Variablen, die nur im Rumpf der
# Schleife verwendet werden, bleiben im Block lokal.
def repeat_while(x)
if x # Wenn die Bedingung nicht nil oder false war
yield # Den Rumpf der Schleife ausführen
retry # retry, um die Schleifenbedingung erneut auszuwerten
end
end
5.5.6 throw und catch
throw
und
catch
sind Kernel-Methoden, die eine Kontrollstruktur definieren, die man sich als mehrstufiges
break
vorstellen kann.
throw
bricht nicht nur aus der aktuellen Schleife oder dem aktuellen Block aus, sondern kann tatsächlich beliebig viele Stufen durchqueren, wodurch der mittels
catch
definierte Block beendet wird. Das
catch
braucht sich noch nicht einmal in derselben Methode zu befinden wie das
throw
. Es kann sich in der aufrufenden Methode oder sogar noch weiter oben im Call-Stack befinden.
Sprachen wie Java und JavaScript erlauben Ihnen, Schleifen mit einem beliebigen Präfix zu benennen oder zu kennzeichnen. Wenn das geschehen ist, sorgt eine Kontrollstruktur namens »labeled break« dafür, dass die benannte Schleife beendet wird. Rubys
catch
-Methode definiert einen Codeblock mit Label, und Rubys
throw
-Methode sorgt dafür, dass dieser Block beendet wird. Aber
throw
und
catch
sind viel allgemeingültiger als ein
break
mit Label. Zuerst einmal können sie mit jeder Art von Anweisung verwendet werden und sind nicht auf Schleifen beschränkt. Bei näherer Betrachtung kann ein
throw
den Call-Stack hinauf weitergegeben werden und so dafür sorgen, dass ein Block in einer aufrufenden Methode beendet wird.
Wenn Sie mit Sprachen wie Java und JavaScript vertraut sind, erkennen Sie
throw
und
catch
wahrscheinlich als die Schlüsselwörter, die diese Sprachen verwenden, um Ansnahmen auszulösen und zu behandeln. Ruby geht anders mit Ausnahmen um und verwendet
raise
und
rescue
dafür, die Sie weiter unten in diesem Kapitel kennenlernen. Aber die Parallele zu den Ausnahmen ist Absicht. Der Aufruf von
throw
ähnelt stark dem Auslösen einer Ausnahme. Und die Art und Weise, wie ein
throw
den lexikalischen Gültigkeitsbereich überwindet und den Call-Stack hinauf weitergegeben wird, entspricht genau der Art und Weise, wie eine Ausnahme das tut. (Wir werden weiter unten in diesem Kapitel viel mehr über die Weitergabe von Ausnahmen erfahren.) Trotz der Ähnlichkeit mit Ausnahmen ist es am besten,
throw
und
catch
als allgemeingültige (wenn auch möglicherweise unregelmäßig genutzte) Kontrollstrukturen zu betrachten und nicht als Ausnahmemechanismen. Wenn Sie einen Fehler oder einen
Weitere Kostenlose Bücher