2012-03-13 8 views
5

De acuerdo con The Ruby Programming Language p.164.¿Cómo se determina el valor de un bloque begin?

Si una declaración begin no se propaga a una excepción, entonces el valor de la declaración es el valor de la última expresión evaluada en los begin, rescue o else cláusulas.

Pero encontré este comportamiento consistente con la comienzan bloque junto con cláusula else y garantizar cláusula.

Aquí es el código de ejemplo:

def fact (n) 
    raise "bad argument" if n.to_i < 1 
end 

value = begin 
    fact (1) 
rescue RuntimeError => e 
    p e.message 
else 
    p "I am in the else statement" 
ensure 
    p "I will be always executed" 
    p "The END of begin block" 
end 

p value 

La salida es:

"I am in the else statement" 
"I will be always executed" 
"The END of begin block" 
"I am in the else statement" 
[Finished] 

El value se evalúa a la cláusula else. Este es un comportamiento incoherente ya que asegura la cláusula es la última instrucción ejecutada.

¿Podría alguien explicar lo que está sucediendo dentro del bloque de comenzar?

+0

"bloque de código se evalúa para la última sentencia ejecutada". Esta es obviamente una suposición equivocada. –

+0

Disculpe, corrija con declaraciones y referencias más específicas. – steveyang

+2

Ahora usted mismo ha respondido a la pregunta: "begin, rescue or else" es, de hecho, el orden correcto, por lo que esto es coherente con la especificación. –

Respuesta

4

me gustaría interpretar el objetivo del bloque begin/rescue/else/end como:

  • ejecutar el código en la sección begin, y luego el código de la sección else.
  • Si algo sale mal en la sección begin, ejecute la sección rescue en lugar de la sección else.

Así ya sea la sección rescue o la sección else se ejecutarán después de probar la sección begin; entonces tiene sentido que uno de ellos se use como el valor total del bloque.

Es simplemente un efecto secundario que la sección ensure siempre se ejecutará.

val = begin 
    p "first"; "first" 
rescue => e 
    p "fail"; "fail" 
else 
    p "else"; "else" 
ensure 
    p "ensure"; "ensure" 
end 

val # => "else" 
# >> "first" 
# >> "else" 
# >> "ensure" 

Pero:

val = begin 
    p "first"; "first" 
    raise 
rescue => e 
    p "fail"; "fail" 
else 
    p "else"; "else" 
ensure 
    p "ensure"; "ensure" 
end 

val # => "fail" 
# >> "first" 
# >> "fail" 
# >> "ensure" 
0

Solo estoy adivinando aquí, pero como el propósito de un bloque de seguridad es finalizar cualquier recurso que pueda permanecer abierto (limpieza en otras palabras), por lo que tiene sentido que el valor lógico sea el resultado del declaración else Para mí tiene sentido que sea por diseño.

0

En este caso, el bloque begin es solo una forma de definir una sección para la que es posible que desee hacer un manejo de excepciones.

Recuerde que else en este caso se ejecuta si no se producen excepciones, y ensure se ejecutará independientemente de las excepciones o la falta de las mismas.

Cuestiones relacionadas