Um aus tief verschachtelten Strukturen den Programmfluss über mehrere Ebenen
hinweg zu ändern,
stellt Ruby das (auch in Lisp vorhandene) Idiom
throw und catch zur Verfügung.
kombi = "#{rand(10)}#{rand(10)}"
p geraten = catch(:gefunden) {
(0..9).each { |a|
(0..9).each { |b|
test = "#{a}#{b}#{c}"
throw(:gefunden, test) if test == kombi
}
}
nil
}
Die im catch-Block aufgeführten Anweisungen werden abgearbeitet, bis
die throw-Anweisung in einem Zug aus der innersten Schleife zurück
auf die zugehörige catch-Ebene springt.
Dabei kann wie im Beispiel ein Objekt "`geworfen"' werden, das die mit dem
gleichen Symbol bereitgestellte catch-Anweisung "`auffängt"'.
Fehlt ein korrespondierendes catch, so produziert Ruby
einen NameError: uncaught throw '...'.
Die Schreibweise :dings bezeichnet ein Symbol mit dem Namen
"`dings"'. Symbole sind interne Repräsentationen, die für den jeweiligen
String eindeutig sind:
:dings.id #-> 3619086
"dings".intern.id #-> 3619086
("d"+"ings").intern.id #-> 3619086
Bei Bedarf können mehrere catch-Blöcke verschachtelt
werden, was aber schnell unübersichtlich wird. Anzumerken ist noch, dass
erst während der Ausführung der throw-Anweisung ein passendes catch
aktiv sein muss.
def wurf; throw :faenger, "ball"; end
catch(:faenger) { wurf } #-> "ball"
wurf #-> NameError