Ruby a deux mécanismes d'exceptions différents: Throw / Catch et Raise / Rescue.
Pourquoi en avons-nous deux?
Quand devriez-vous utiliser l'un et pas l'autre?
Ruby a deux mécanismes d'exceptions différents: Throw / Catch et Raise / Rescue.
Pourquoi en avons-nous deux?
Quand devriez-vous utiliser l'un et pas l'autre?
Réponses:
Je pense que http://hasno.info/ruby-gotchas-and-caveats a une explication décente de la différence:
catch / throw n'est pas la même chose que relancer / sauver. catch / throw vous permet de quitter rapidement les blocs pour revenir à un point où un catch est défini pour un symbole spécifique, le sauvetage de la levée est le vrai traitement des exceptions impliquant l'objet Exception.
raise
c'est très cher. throw
n'est pas. Pensez throw
à utiliser goto
pour sortir d'une boucle.
raise
, fail
, rescue
Et ensure
poignée erreurs , également connu sous le nom des exceptionsthrow
et catch
sont flux de contrôleContrairement à d'autres langages, le throw et le catch de Ruby ne sont pas utilisés pour les exceptions. Au lieu de cela, ils fournissent un moyen de terminer l'exécution plus tôt lorsqu'aucun travail supplémentaire n'est nécessaire. (Grimm, 2011)
Terminer un seul niveau de flux de contrôle, comme une while
boucle, peut être fait avec un simple return
. La terminaison de nombreux 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 le traitement normal. C'est là que la capture et le lancer sont utiles. (Thomas et Hunt, 2001)
https://coderwall.com/p/lhkkug/don-t-confuse-ruby-s-throw-statement-with-raise offre une excellente explication que je doute que je puisse améliorer. Pour résumer, en récupérant quelques exemples de code du billet de blog au fur et à mesure:
raise
/ rescue
sont les analogues les plus proches de la construction throw
/ catch
que vous connaissez d'autres langages (ou de raise
/ de Python except
). Si vous avez rencontré une condition d'erreur et que vous la surmonteriez throw
dans une autre langue, vous devriez raise
en Ruby.
Ruby throw
/ catch
vous permet d'interrompre l'exécution et de monter dans la pile à la recherche d'un catch
(comme raise
/ rescue
fait), mais n'est pas vraiment destiné aux conditions d'erreur. Il devrait être utilisé rarement, et est là uniquement lorsque le catch
comportement «remonter la pile jusqu'à ce que vous trouviez un correspondant » a du sens pour un algorithme que vous écrivez, mais cela n'aurait pas de sens de penser que le throw
comme correspondant à une erreur état.
À quoi sert le catch and throw dans Ruby? propose quelques suggestions sur les bonnes utilisations de throw
/ catch
construct.
Les différences de comportement concrètes entre eux comprennent:
rescue Foo
sauvera des instances d' Foo
inclusion de sous-classes de Foo
. catch(foo)
ne fonctionnera que pour le même objet,Foo
. Non seulement vous ne pouvez pas passer catch
un nom de classe pour en attraper des instances, mais cela ne fera même pas de comparaisons d'égalité. Par exemple
catch("foo") do
throw "foo"
end
vous donnera une UncaughtThrowError: uncaught throw "foo"
(ou une ArgumentError
version in de Ruby antérieure à 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
es doivent être imbriquées ...
catch :foo do
catch :bar do
do_something_that_can_throw_foo_or_bar
end
end
Un nu rescue
équivaut à rescue StandardError
et est une construction idiomatique. Un "nu catch
", comme catch() {throw :foo}
, n'attrapera jamais rien et ne devrait pas être utilisé.
goto
en C / C ++ comme @docwhat a mentionné, Java a marqué break et continue . (Python a également une proposition rejetée pour cela.)