ruby-on-rails - try - ruby standard error
¿Comenzar, rescatar y asegurar en Ruby? (7)
Para su información, incluso si se vuelve a elevar una excepción en la sección de rescue
, el bloque de garantía se ejecutará antes de que la ejecución del código continúe en el siguiente controlador de excepciones. Por ejemplo:
begin
raise "Error!!"
rescue
puts "test1"
raise # Reraise exception
ensure
puts "Ensure block"
end
Recientemente empecé a programar en Ruby, y estoy mirando el manejo de excepciones.
Me preguntaba si la ensure
era el equivalente de Ruby finally
en C #. Debería tener:
file = File.open("myFile.txt", "w")
begin
file << "#{content} /n"
rescue
#handle the error here
ensure
file.close unless file.nil?
end
o debo hacer esto?
#store the file
file = File.open("myFile.txt", "w")
begin
file << "#{content} /n"
file.close
rescue
#handle the error here
ensure
file.close unless file.nil?
end
¿ ensure
se llame sin importar qué, incluso si no se produce una excepción?
Por eso necesitamos ensure
:
def hoge
begin
raise
rescue
raise # raise again
ensure
puts ''ensure'' # will be executed
end
puts ''end of func'' # never be executed
end
Sí, ensure
ENSURES se ejecute cada vez, para que no necesite el file.close
en el bloque de begin
.
Por cierto, una buena manera de probar es hacer:
begin
# Raise an error here
raise "Error!!"
rescue
#handle the error here
ensure
p "=========inside ensure block"
end
Puede realizar una prueba para ver si se imprime "========= dentro del bloque de garantía" cuando haya una excepción. Luego puede comentar la declaración que genera el error y ver si la declaración de garantía se ejecuta al ver si algo se imprime.
Sí, ensure
que finally
garantiza que el bloque será ejecutado . Esto es muy útil para asegurarse de que los recursos críticos estén protegidos, por ejemplo, cerrar un identificador de archivo en caso de error o liberar un mutex.
Sí, ensure
que el código siempre sea evaluado. Por eso se llama ensure
. Entonces, es equivalente a Java y C # finally
.
El flujo general de begin
/ rescue
/ else
/ ensure
/ end
ve así:
begin
# something which might raise an exception
rescue SomeExceptionClass => some_variable
# code that deals with some exception
rescue SomeOtherException => some_other_variable
# code that deals with some other exception
else
# code that runs only if *no* exception was raised
ensure
# ensure that this code always runs, no matter what
# does not change the final value of the block
end
Usted puede dejar de rescue
, ensure
o de lo else
. También puede omitir las variables, en cuyo caso no podrá inspeccionar la excepción en su código de manejo de excepciones. (Bueno, siempre puede usar la variable de excepción global para acceder a la última excepción que se generó, pero eso es un poco intrépido). Y puede omitir la clase de excepción, en cuyo caso se capturarán todas las excepciones heredadas de StandardError
. (Tenga en cuenta que esto no significa que se capturen todas las excepciones, porque hay excepciones que son instancias de Exception
pero StandardError
. Principalmente, excepciones muy severas que comprometen la integridad del programa, como SystemStackError
, NoMemoryError
, SecurityError
, NotImplementedError
, LoadError
, SyntaxError
, ScriptError
, Interrupt
, SignalException
o SystemExit
.)
Algunos bloques forman bloques de excepción implícitos. Por ejemplo, las definiciones de métodos son también implícitamente bloques de excepción, así que en lugar de escribir
def foo
begin
# ...
rescue
# ...
end
end
tu solo escribes
def foo
# ...
rescue
# ...
end
o
def foo
# ...
ensure
# ...
end
Lo mismo se aplica a class
definiciones de class
y las definiciones de module
.
Sin embargo, en el caso específico sobre el que estás preguntando, hay un idioma mucho mejor. En general, cuando trabaja con algún recurso que necesita limpiar al final, lo hace pasando un bloque a un método que hace toda la limpieza por usted. Es similar a un bloque de using
en C #, excepto que Ruby es lo suficientemente poderoso como para que no tengas que esperar a que los sumos sacerdotes de Microsoft bajen de la montaña y cambien amablemente su compilador. En Ruby, puedes implementarlo tú mismo:
# This is what you want to do:
File.open(''myFile.txt'', ''w'') do |file|
file.puts content
end
# And this is how you might implement it:
def File.open(filename, mode=''r'', perm=nil, opt=nil)
yield filehandle = new(filename, mode, perm, opt)
ensure
filehandle&.close
end
Y qué sabe: esto ya está disponible en la biblioteca central como File.open
. Pero es un patrón general que también puede usar en su propio código, para implementar cualquier tipo de limpieza de recursos (a la using
en C #) o transacciones o cualquier otra cosa que pueda pensar.
El único caso donde esto no funciona, si la adquisición y la liberación del recurso se distribuyen en diferentes partes del programa. Pero si está localizado, como en su ejemplo, entonces puede usar fácilmente estos bloques de recursos.
Por cierto: en C # moderno, el using
es realmente superfluo, porque puedes implementar tú mismo los bloques de recursos de estilo Ruby:
class File
{
static T open<T>(string filename, string mode, Func<File, T> block)
{
var handle = new File(filename, mode);
try
{
return block(handle);
}
finally
{
handle.Dispose();
}
}
}
// Usage:
File.open("myFile.txt", "w", (file) =>
{
file.WriteLine(contents);
});
Sí, ensure
se llama en cualquier circunstancia. Para obtener más información, consulte " Excepciones, captura y lanzamiento " del libro de programación de Ruby y busque "asegurar".
Si desea asegurarse de que un archivo está cerrado, debe usar la forma de bloque de File.open
:
File.open("myFile.txt", "w") do |file|
begin
file << "#{content} /n"
rescue
#handle the error here
end
end