Quelle est la différence entre lever des exceptions et lancer des exceptions dans Ruby ?
Question
Ruby a deux mécanismes d'exceptions différents :Lancer/attraper et relancer/sauvetage.
Pourquoi en avons-nous deux ?
Quand faut-il utiliser l’un et pas l’autre ?
La solution
Je pense http://hasno.info/ruby-gotchas-and-caveats a une explication décente de la différence:
attraper/lancer ne sont pas la même chose que relancer/sauvetage.catch/throw vous permet de quitter rapidement les blocs jusqu'à un point où un catch est défini pour un symbole spécifique, raise Rescue est le véritable élément de gestion des exceptions impliquant l'objet Exception.
Autres conseils
raise
,fail
,rescue
, etensure
poignée les erreurs, aussi connu sous le nom des exceptionsthrow
etcatch
sont flux de contrôle
Contrairement à d'autres langues, le lancer et les captures de Ruby ne sont pas utilisés pour des exceptions.Au lieu de cela, ils fournissent un moyen de mettre fin à l'exécution tôt lorsqu'aucun autre travail n'est nécessaire.(Grimm, 2011)
Terminer un seul niveau de flux de contrôle, comme un while
boucle, peut être fait avec un simple return
.La terminaison de plusieurs niveaux de flux de contrôle, comme une boucle imbriquée, peut être effectuée avec throw
.
Bien que le mécanisme d'exception de relance et de sauvetage soit idéal pour abandonner l'exécution lorsque les choses tournent mal, il est parfois agréable de pouvoir sortir d'une construction profondément imbriquée pendant un traitement normal.C’est là que attraper et lancer s’avère utile.(Thomas et Hunt, 2001)
Les références
- Grimm, Avdi."Jetez, attrapez, soulevez, sauvez ... je suis tellement confus!" Blog RubyLearning.N.p., 11 juillet 2011.La toile.1er janvier2012. http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/.
- Thomas, Dave et Andrew Hunt."Programmation Ruby." :Le guide du programmeur pragmatique.N.p., 2001.La toile.29 sept.2015. http://ruby-doc.com/docs/ProgrammingRuby/html/tut_exceptions.html.
https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise offre une excellente explication que je doute de pouvoir améliorer.Pour résumer, en reprenant quelques exemples de code du billet de blog au fur et à mesure :
raise
/rescue
sont les analogues les plus proches duthrow
/catch
construction que vous connaissez dans d'autres langages (ou dans Pythonraise
/except
).Si vous avez rencontré une condition d'erreur et que vousthrow
dessus dans une autre langue, vous devriezraise
en Rubis.chez Ruby
throw
/catch
vous permet d'interrompre l'exécution et de gravir la pile à la recherche d'uncatch
(commeraise
/rescue
le fait), mais n'est pas vraiment destiné aux conditions d'erreur.Il devrait être utilisé rarement, et n'est-il là que lorsque "montez la pile jusqu'à ce que vous trouviez un correspondantcatch
" le comportement a du sens pour un algorithme que vous écrivez, mais cela n'aurait aucun sens de penser authrow
comme correspondant à une condition d’erreur.À quoi servent le catch and throw dans Ruby ? propose quelques suggestions sur des utilisations intéressantes du
throw
/catch
construction.
Les différences comportementales concrètes entre eux comprennent :
rescue Foo
sauvera des cas deFoo
y compris les sous-classes deFoo
.catch(foo)
ne fera qu'attraper le même objet,Foo
.Non seulement tu ne peux pas passercatch
un nom de classe pour en détecter les instances, mais il ne fera même pas de comparaisons d'égalité.Par exemplecatch("foo") do throw "foo" end
vous donnera un
UncaughtThrowError: uncaught throw "foo"
(ou unArgumentError
dans les versions de Ruby antérieures à 2.2)Plusieurs clauses de sauvetage peuvent être répertoriées...
begin do_something_error_prone rescue AParticularKindOfError # Insert heroism here. rescue write_to_error_log raise end
alors que plusieurs
catch
il faut les imbriquer...catch :foo do catch :bar do do_something_that_can_throw_foo_or_bar end end
Un nu
rescue
est équivalent àrescue StandardError
et est une construction idiomatique.Un nucatch
", commecatch() {throw :foo}
, n'attrapera jamais rien et ne devrait pas être utilisé.