¿Cuál es la diferencia entre generar excepciones y lanzar excepciones en Ruby?
Pregunta
Ruby tiene dos mecanismos de excepción diferentes:Lanzar/Atrapar y Levantar/Rescatar.
¿Por qué tenemos dos?
¿Cuándo deberías usar uno y no el otro?
Solución
Creo http://hasno.info/ruby-gotchas-and-caveats tiene una explicación decente de la diferencia:
atrapar/lanzar no es lo mismo que subir/rescatar.catch/throw le permite salir rápidamente de los bloques hasta un punto donde se define una captura para un símbolo específico, elevar el rescate es el verdadero manejo de excepciones que involucra el objeto Exception.
Otros consejos
raise
,fail
,rescue
, yensure
manejar errores, también conocido como excepcionesthrow
ycatch
son flujo de control
A diferencia de otros idiomas, el lanzamiento y la captura de Ruby no se usan para excepciones.En cambio, proporcionan una forma de terminar la ejecución temprano cuando no se necesita más trabajo.(Grimm, 2011)
Terminar un único nivel de flujo de control, como un while
bucle, se puede hacer con un simple return
.La terminación de muchos niveles de flujo de control, como un bucle anidado, se puede hacer con throw
.
Si bien el mecanismo de excepción de aumento y rescate es excelente para abandonar la ejecución cuando las cosas van mal, a veces es bueno poder saltar de alguna construcción profundamente anidada durante el procesamiento normal.Aquí es donde resulta útil atrapar y lanzar.(Thomas y Hunt, 2001)
Referencias
- Grimm, Avdi."Lanza, atrapa, cría, rescate ... ¡Estoy tan confundido!" Blog de RubyLearning.Np, 11 de julio de 2011.Web.1 de enero.2012. http://rubylearning.com/blog/2011/07/12/throw-catch-raise-rescue--im-so-confused/.
- Thomas, Dave y Andrew Hunt."Programación de Ruby". :La guía pragmática del programador.Np, 2001.Web.29 de septiembre.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 Ofrece una excelente explicación que dudo que pueda mejorar.Para resumir, tomando algunos ejemplos de código de la publicación del blog a medida que avanzo:
raise
/rescue
son los análogos más cercanos a lathrow
/catch
construcción con la que está familiarizado en otros lenguajes (o en Python)raise
/except
).Si ha encontrado una condición de error y deseathrow
sobre él en otro idioma, deberíasraise
en Rubí.rubí
throw
/catch
te permite interrumpir la ejecución y subir por la pila en busca de uncatch
(comoraise
/rescue
lo hace), pero en realidad no está destinado a condiciones de error.Debe usarse raramente y está ahí sólo para cuando "sube por la pila hasta encontrar el correspondiente".catch
"El comportamiento tiene sentido para un algoritmo que estás escribiendo, pero no tendría sentido pensar en elthrow
como correspondiente a una condición de error.¿Para qué se utiliza atrapar y lanzar en Ruby? ofrece algunas sugerencias sobre buenos usos del
throw
/catch
construir.
Las diferencias concretas de comportamiento entre ellos incluyen:
rescue Foo
rescatará casos deFoo
incluyendo subclases deFoo
.catch(foo)
sólo atrapará el mismo objeto,Foo
.No sólo no puedes pasarcatch
un nombre de clase para detectar instancias del mismo, pero ni siquiera hará comparaciones de igualdad.Por ejemplocatch("foo") do throw "foo" end
te daré un
UncaughtThrowError: uncaught throw "foo"
(o unArgumentError
en versiones de Ruby anteriores a la 2.2)Se pueden enumerar múltiples cláusulas de rescate...
begin do_something_error_prone rescue AParticularKindOfError # Insert heroism here. rescue write_to_error_log raise end
mientras que múltiples
catch
es necesita estar anidado...catch :foo do catch :bar do do_something_that_can_throw_foo_or_bar end end
Un desnudo
rescue
es equivalente arescue StandardError
y es una construcción idiomática.Un desnudocatch
", comocatch() {throw :foo}
, nunca atrapará nada y no debe usarse.