«Sortir des boucles imbriquées» est un besoin courant dans de nombreux langages de programmation. Outre le gotoen C / C ++ comme @docwhat a mentionné, Java a marqué break et continue . (Python a également une proposition rejetée pour cela.)
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.
Curieux de savoir ... En lisant ceci à partir d'un iPad, vous ne pouvez donc pas les tester dans la version 1.9, mais certains de ces pièges ne sont plus valables dans les versions récentes de ruby, non?
Denis de Bernardy
12
A savoir également: raisec'est très cher. thrown'est pas. Pensez throwà utiliser gotopour sortir d'une boucle.
raise, fail, rescueEt ensurepoignée erreurs , également connu sous le nom des exceptions
throwet catchsont flux de contrôle
Contrairement à 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 whileboucle, 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)
Drôle, rubylearning.com pense que l'article d'Avdi est toujours là . Je suppose que c'est pourquoi nous copions des trucs vers SO, pour qu'ils ne soient pas perdus!
raise/ rescuesont les analogues les plus proches de la construction throw/ catchque vous connaissez d'autres langages (ou de raise/ de Python except). Si vous avez rencontré une condition d'erreur et que vous la surmonteriez throwdans une autre langue, vous devriez raiseen Ruby.
Ruby throw/ catchvous permet d'interrompre l'exécution et de monter dans la pile à la recherche d'un catch(comme raise/ rescuefait), mais n'est pas vraiment destiné aux conditions d'erreur. Il devrait être utilisé rarement, et est là uniquement lorsque le catchcomportement «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 throwcomme correspondant à une erreur état.
Les différences de comportement concrètes entre eux comprennent:
rescue Foosauvera des instances d' Fooinclusion de sous-classes de Foo. catch(foo)ne fonctionnera que pour le même objet,Foo . Non seulement vous ne pouvez pas passer catchun 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 ArgumentErrorversion in de Ruby antérieure à 2.2)
Plusieurs clauses de sauvetage peuvent être répertoriées ...
begin
do_something_error_prone
rescueAParticularKindOfError# Insert heroism here.rescue
write_to_error_log
raise
end
alors que plusieurs catches doivent être imbriquées ...
catch :foo do
catch :bar do
do_something_that_can_throw_foo_or_bar
endend
Un nu rescueéquivaut à rescue StandardErroret est une construction idiomatique. Un "nu catch", comme catch() {throw :foo}, n'attrapera jamais rien et ne devrait pas être utilisé.
Bonne explication mais soulève la question, pourquoi diable voudraient-ils concevoir augmenter en rubis = jeter dans une autre langue. puis incluez également throw mais it! = throw dans d'autres langues. Je ne peux pas voir leur logique d'origine là
wired00
@ wired00 ( Shrug .) Je suis d'accord que cela semble assez excentrique par rapport aux autres langues populaires aujourd'hui.
Mark Amery
2
@ wired00: On l'appelle "lever" une exception depuis les toutes premières expériences de gestion structurée des erreurs dans les années 1960, on l'appelle "lever" une exception dans les articles fondateurs qui ont inventé la forme moderne de gestion des exceptions, on l'appelle "lever" une exception dans Lisps et Smalltalks, qui étaient quelques-unes des principales inspirations de Ruby, et cela s'appelle "lever" une exception ou "lever" une interruption dans le matériel, où le concept existait avant même le concept d'une "programmation la langue "existait. La question devrait plutôt être: pourquoi ces autres langues ont-elles changé cela?
Jörg W Mittag
@MarkAmery: Souvenez-vous que beaucoup de ces "autres langues populaires" sont plus jeunes que Ruby ou du moins contemporaines. Donc, la question devrait plutôt être: pourquoi ces autres langages n'ont-ils pas suivi Ruby (et Smalltalk et Lisp et le matériel et la littérature).
Jörg W Mittag
@ JörgWMittag Intéressant - vous m'avez inspiré pour faire un peu de recherche historique. C ++ avait la notion de "lancer" une exception des années avant l'arrivée de Ruby, et selon english.stackexchange.com/a/449209/73974, le terme remonte en fait aux années 70 ... donc je pense que nous pouvons encore critiquer Ruby pour prendre une terminologie établie et l'utiliser pour signifier quelque chose de complètement différent.
goto
en C / C ++ comme @docwhat a mentionné, Java a marqué break et continue . (Python a également une proposition rejetée pour cela.)Réponses:
Je pense que http://hasno.info/ruby-gotchas-and-caveats a une explication décente de la différence:
la source
raise
c'est très cher.throw
n'est pas. Pensezthrow
à utilisergoto
pour sortir d'une boucle.raise
,fail
,rescue
Etensure
poignée erreurs , également connu sous le nom des exceptionsthrow
etcatch
sont flux de contrôleTerminer un seul niveau de flux de contrôle, comme une
while
boucle, peut être fait avec un simplereturn
. La terminaison de nombreux niveaux de flux de contrôle, comme une boucle imbriquée, peut être effectuée avecthrow
.Références
la source
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 constructionthrow
/catch
que vous connaissez d'autres langages (ou deraise
/ de Pythonexcept
). Si vous avez rencontré une condition d'erreur et que vous la surmonteriezthrow
dans une autre langue, vous devriezraise
en Ruby.Ruby
throw
/catch
vous permet d'interrompre l'exécution et de monter dans la pile à la recherche d'uncatch
(commeraise
/rescue
fait), mais n'est pas vraiment destiné aux conditions d'erreur. Il devrait être utilisé rarement, et est là uniquement lorsque lecatch
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 lethrow
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 deFoo
.catch(foo)
ne fonctionnera que pour le même objet,Foo
. Non seulement vous ne pouvez pas passercatch
un nom de classe pour en attraper des instances, mais cela ne fera même pas de comparaisons d'égalité. Par exemplevous donnera une
UncaughtThrowError: uncaught throw "foo"
(ou uneArgumentError
version in de Ruby antérieure à 2.2)Plusieurs clauses de sauvetage peuvent être répertoriées ...
alors que plusieurs
catch
es doivent être imbriquées ...Un nu
rescue
équivaut àrescue StandardError
et est une construction idiomatique. Un "nucatch
", commecatch() {throw :foo}
, n'attrapera jamais rien et ne devrait pas être utilisé.la source