Ja, ensure
stellt 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
/ end
sieht 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
, ensure
oder 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 StandardError
abgefangen , von denen geerbt wird. (Bitte beachten Sie, dass dies nicht bedeutet , dass alle Ausnahmen abgefangen werden, denn es gibt Ausnahmen , die Instanzen sind Exception
aber nicht StandardError
. Meistens ist sehr schwere Ausnahmen , dass ein Kompromiss der Integrität des Programms wie SystemStackError
, NoMemoryError
, SecurityError
, NotImplementedError
, LoadError
, SyntaxError
, ScriptError
, Interrupt
,SignalException
oder 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 class
Definitionen und module
Definitionen.
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 using
Block 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 using
in 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 # using
ist 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);
});
begin
Blocks befindet.