Ja, ensurestellt sicher, dass der Code immer ausgewertet wird. Deshalb heißt es ensure. Es ist also äquivalent zu Java und C # finally.
Der allgemeine Ablauf von begin/ rescue/ else/ ensure/ endsieht folgendermaßen aus:
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
Sie können weglassen rescue, ensureoder else. Sie können auch die Variablen weglassen. In diesem Fall können Sie die Ausnahme in Ihrem Ausnahmebehandlungscode nicht überprüfen. (Nun, Sie können immer die globale Ausnahmevariable verwenden, um auf die letzte Ausnahme zuzugreifen, die ausgelöst wurde, aber das ist ein bisschen hackig.) Und Sie können die Ausnahmeklasse weglassen. In diesem Fall werden alle Ausnahmen StandardErrorabgefangen , von denen geerbt wird. (Bitte beachten Sie, dass dies nicht bedeutet , dass alle Ausnahmen abgefangen werden, denn es gibt Ausnahmen , die Instanzen sind Exceptionaber nicht StandardError. Meistens ist sehr schwere Ausnahmen , dass ein Kompromiss der Integrität des Programms wie SystemStackError, NoMemoryError, SecurityError, NotImplementedError, LoadError, SyntaxError, ScriptError, Interrupt,SignalExceptionoder SystemExit.)
Einige Blöcke bilden implizite Ausnahmeblöcke. Beispielsweise sind Methodendefinitionen implizit auch Ausnahmeblöcke, anstatt zu schreiben
def foo
begin
# ...
rescue
# ...
end
end
du schreibst nur
def foo
# ...
rescue
# ...
end
oder
def foo
# ...
ensure
# ...
end
Gleiches gilt für classDefinitionen und moduleDefinitionen.
In dem speziellen Fall, nach dem Sie fragen, gibt es jedoch tatsächlich eine viel bessere Sprache. Wenn Sie mit einer Ressource arbeiten, die Sie am Ende bereinigen müssen, übergeben Sie im Allgemeinen einen Block an eine Methode, die die gesamte Bereinigung für Sie durchführt. Es ähnelt einem usingBlock in C #, nur dass Ruby tatsächlich so mächtig ist, dass Sie nicht darauf warten müssen, dass die Hohepriester von Microsoft vom Berg herunterkommen und ihren Compiler für Sie ändern. In Ruby können Sie es einfach selbst implementieren:
# 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
Und was wissen Sie: Dies ist bereits in der Kernbibliothek als verfügbar File.open. Es ist jedoch ein allgemeines Muster, das Sie auch in Ihrem eigenen Code verwenden können, um jede Art von Ressourcenbereinigung (à la usingin C #) oder Transaktionen oder was auch immer Sie sonst denken , zu implementieren .
Der einzige Fall, in dem dies nicht funktioniert, wenn der Erwerb und die Freigabe der Ressource auf verschiedene Teile des Programms verteilt sind. Wenn es jedoch wie in Ihrem Beispiel lokalisiert ist, können Sie diese Ressourcenblöcke problemlos verwenden.
Übrigens: Im modernen C # usingist dies eigentlich überflüssig, da Sie Ressourcenblöcke im Ruby-Stil selbst implementieren können:
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);
});
beginBlocks befindet.