Heute ist Syntax-Sonntag! Ab jetzt soll es jede Woche eine neue Kurzgeschichte aus der Syntaxwelt von Ruby geben. Heute:
Man hat einen einfachen begin-rescue-Block, der etwa folgende Form besitzt:
begin clas = Object.const_get 'Foo' rescue clas = nil end
Das kann man vereinfachen, indem man die linke Seite ausklammert:
clas = begin Object.const_get 'Foo' rescue nil end
Oder man benutzt rescue in der Modifikator-Variante, wie if oder unless:
clas = Object.const_get 'Foo' rescue nil
Die Anweisung probiert also zuerst, die Konstante Object::Foo zu finden. Wird sie nicht gefunden, wird ein NameError (uninitialized constant Foo) erzeugt; diesen schluckt der Modifikator und liefert stattdessen nil.
Ein typisches Einsatzgebiet ist die Division mit Werten, die 0 sein könnten:
a, b = 3, 0 q = a/b #-> ZeroDivisionError q = a/b rescue 0 #-> 0
Im Code von ActionMailer habe ich auch folgendes gefunden:
rline = line.dup rescue line
Hier wird versucht, ein Objekt zu duplizieren, bevor es verwendet wird; das ist natürlich sicherer, falls das Objekt zum Beispiel von außen verändert werden könnte (wie bei einer Iteration per each) oder wenn man Bang-methoden (gsub! etc.) aufrufen will. Wenn das Dublizieren fehlschlägt, wird stillscheigend das Original benutzt. Bin mir nicht sicher, ob das so gut ist.
Die Präzedenzregeln sind hier vielleicht etwas überraschend. Bei einer Zuweisung bindet rescue stärker als das Gleichheitszeichen (geändert seit Ruby 1.8); will man jedoch eine Methode mit einem solchen Argument aufrufen, gibt es Probleme:
p a / b rescue 0 #-> nichts wird ausgegeben... (p a / b) rescue 0 #-> ...weil Ruby den Ausdruck so auswertet p((a / b rescue 0)) #-> 0
Gute Nachricht für rastlose Performance-Fanatiker: Ein Modifikator hinter einer Anweisung scheint die Geschwindigkeit nicht zu beeinflussen:
require 'benchmark' N = 100_000 Benchmark.bm 6 do |bm| bm.report 'normal' do N.times do Array(1..5).reverse.sort end end bm.report 'rescue' do N.times do Array(1..5).reverse.sort rescue false end end end __END__ user system total real normal 1.422000 0.000000 1.422000 ( 2.033000) rescue 1.522000 0.000000 1.522000 ( 1.983000)
Kommentar schreiben
Kommentare
Das verbesserte Script zum Highlighten sorgt dafür, dass die WordPress die Anführungszeichen in Ruhe lässt.
ich muss sagen die variante clas = begin Object.const_get 'Foo' rescue nil end wirkt unuebersichtlich. dann ist der normale geschriebene block schon besser find ich persoenlich. ausser man ist schreibfaul - warum sollte man diese unuebersichtliche variante nutzen?
Ich würde sagen es spart die doppelte Verwendung des Bezeichners :class. Syntax sugar halt. Btw. interessanter Artikel, besonders der Hinweis auf die ActionMailer Bibliothek. Allgemein scheint es zum guten Ton zu gehören Fehlermeldungen einfach zu unterdrücken. Ich kann nicht so ganz beurteilen wie problematisch das werden kann, im Moment scheint es ja noch gut zu funktionieren. Mein Tipp ist jedoch, für erwartete Zustände auch eine Annahme im Code aufzuführen. Wenn ich z.B. über eine Datei iterieren dann ist ganz klar, dass ich irgendwann EOF bekomme. Da muss man das Programm doch nicht unbedingt auf eine Exception laufen lassen.
[...] Murphy hat Euch in den letzten Wochen, einen tiefen Einblick in die syntaktischen Finessen von Ruby geliefert. Ihr habt normale Strings und Fancy Strings kennengelernt. Es stellte sich heraus, dass Here Docs ebenfalls nur Strings, mit einer zusätzlichen Dimension, sind. Die funktionale Programmierung mit proc Objekten macht Euch das Leben um einiges leichter. Und ein exception handling mit rescue ist nun zu einem selbstverständlichen Codefragment geworden, welches jeden unsicheren Code schmückt. Parallel hierzu möchten wir euch nun auf einer neuen Ebene einen Einblick in unseren Rubin verschaffen. Hierzu fahren wir die Schmelzanlage auf knapp 2050°C hoch und schauen uns an, was sich im inneren des Edelsteins befindet. [...]
Schön. Sowas wie: rescue Mist, Dreck also Mist oder Dreck, geht auch. Hatte ich in keiner Doku gefunden. Falls jemand hier danach sucht.