2010-01-07 13 views
10

Realmente no veo un uso sensato para estos. Ya hay rescue y raise, ¿por qué la necesidad de throw y catch? Parece que se supone que deben usarse para saltar desde un anidamiento profundo, pero eso me huele a goto. ¿Hay algún ejemplo de uso bueno y limpio para estos?¿Dónde es útil coger y tirar en Ruby?

Respuesta

6

Nota: Parece que algunas cosas han cambiado con catch/throw en 1.9. Esta respuesta se aplica a Ruby 1.9.

Una gran diferencia es que puede throw cualquier cosa, no solo las cosas que se derivan de StandardError, a diferencia de raise. Algo así de tonto es legal, por ejemplo:

throw Customer.new 

pero no es terriblemente significativo. Pero no se puede hacer:

irb(main):003:0> raise Customer.new 
TypeError: exception class/object expected 
    from (irb):3:in `raise' 
    from (irb):3 
    from /usr/local/bin/irb:12:in `<main>' 
+0

El ejemplo es legal con un rescate/aumento, también. Simplemente dice "clase o módulo requerido para la cláusula de rescate". –

+0

Además, me dice que solo puede atrapar/lanzar un símbolo. –

+0

@jleedev »¿Qué versión de Ruby estás ejecutando? [edit: Vaya, leí mal lo que dijiste. Hice un error al escribir la última frase, lo arreglaré.] –

2

Es básicamente un goto, y un poco más parecido a una llamada/cc, excepto que el flujo de control está cableado implícitamente por nombre en lugar de explícitamente como un parámetro. La diferencia entre throw/catch y raise/rescue es que la primera está destinada a ser utilizada para el flujo de control en lugar de solo situaciones excepcionales, y no pierde tiempo armando un seguimiento de pila.

Sinatra utiliza throw/catch para los códigos de error HTTP, donde un manejador puede usar throw para ceder el control a la biblioteca de Sinatra de una manera estructurada. Otros tipos de marcos HTTP usan excepciones o devuelven una clase diferente de respuesta, pero esto permite a Sinatra (por ejemplo) probar otro manejador de solicitudes después de atraparlo.

1

La diferencia entre los dos es que se puede únicas excepciones 'levantar', pero puede 'tirar' nada (1,9). Aparte de eso, deberían ser intercambiables, es decir, debería ser posible reescribir uno con otro, al igual que el ejemplo dado por @ john-feminella.

5

Pueden ser realmente útil para simplificar DSL para los usuarios finales mediante el paso de control fuera de la DSL, sin necesidad de caso complejo/if

tengo una aplicación de Rubí que permite a los usuarios ampliar que a través de una DSL interno. Algunas de las funciones de la DSL necesitan devolver el control a partes específicas de mi aplicación. Tomemos un ejemplo simple. Supongamos que el usuario está desarrollando una simple extensión en relación con las fechas

if today is a holiday then 
    do nothing 
end 

week_of_year = today.week.number 

if week_of_year < 10 then 

... 

El bit do nothing dispara un tiro que pasa el control de la declaración ejecutivo y de vuelta a mí.

En lugar de seguir ejecutando el DSL, con alguna condición, queremos que salga y devuelva el control a mi aplicación. Ahora puede hacer que el usuario use muchas sentencias if incrustadas y que el DSL termine de forma natural, pero eso simplemente oscurece lo que la lógica está tratando de decir.

Lanzar realmente es un goto que es 'considerado peligroso' pero maldita sea que a veces son la mejor solución.