2011-06-03 13 views
9

consideran este comenzará-rescate-garantizar bloque:Rubí no 'garantizar' cuando yo vuelva a intentar 'en 'rescate'

attempts=0 
begin 
    make_service_call() 
rescue Exception 
    retry unless attempts>2 
    exit -1 
ensure 
    attemps += 1 
end 

Si ejecuta el código tal como es, se produce una excepción porque no hay ninguna función llamada 'make_service_call()'. Entonces, vuelve a intentar. Pero estaría atrapado en un bucle infinito porque el control nunca pasa a 'garantizar' debido a 'reintento'. ¿No se debe 'asegurar' una parte del bloque para garantizar que el código que se ejecuta se ejecute sin importar lo que ocurra en 'comenzar' o 'rescatar'?

Por supuesto que puedo incrementar el conteo en 'comenzar' - ese no es el punto. Solo estoy haciendo la pregunta sobre "asegurar" para obtener un poco de claridad.

Respuesta

17

La sección ensure se ejecuta al salir de la begin declaración (por cualquier medio), pero cuando se retry, sólo estás moverse dentro de la instrucción por lo que la sección de garantizar que no se ejecutará.

Pruebe esta versión de su ejemplo, para obtener una mejor idea de lo que está pasando:

attempts = 0 
begin 
    make_service_call() 
rescue Exception 
    attempts += 1 
    retry unless attempts > 2 
    exit -1 
ensure 
    puts "ensure! #{attempts}" 
end 
2

ensure código se ejecuta una vez, justo antes de las salidas de bloques de código y que se ser llamado en ese momento.

Pero debido a la condición unless attempts>2, y el hecho de que sólo se ensure se llamará "justo antes de las salidas de código" no se ejecutarán (por ejemplo, debido a exit -1) la attempts += 1, y por lo que hay un bucle infinito.

ensure es como __finally en C++: se podía catch la excepción y luego usar un goto: finally pero no se llamará hasta que la función es en realidad a punto de salir.

Cuestiones relacionadas