Commencer, de Sauvetage et d'Assurer à Ruby?
J'ai récemment commencé la programmation en Ruby, et je suis à la recherche sur la gestion des exceptions.
Je me demandais si ensure
était le Rubis équivalent de finally
en C#? Je devrais avoir:
file = File.open("myFile.txt", "w")
begin
file << "#{content} \n"
rescue
#handle the error here
ensure
file.close unless file.nil?
end
ou dois-je faire cela?
#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
Ne ensure
être appelé de n'importe quoi, même si une exception n'est pas soulevée?
- Aucune n'est bonne. En règle générale, lorsque vous traitez avec des ressources externes, vous toujours voulez que la ressource d'ouverture à l'intérieur de la
begin
bloc.
Vous devez vous connecter pour publier un commentaire.
Oui,
ensure
assure que le code est toujours évalué. C'est pourquoi il est appeléensure
. Donc, il est équivalent à Java et C#'sfinally
.Le flux général de
begin
/rescue
/else
/ensure
/end
ressemble à ceci:Vous pouvez laisser de côté
rescue
,ensure
ouelse
. Vous pouvez également laisser les variables dans ce cas, vous ne serez pas en mesure d'inspecter l'exception dans votre code de gestion des exceptions. (Eh bien, vous pouvez toujours utiliser le mondial exception de la variable pour accéder à la dernière exception qui a été soulevée, mais c'est un peu hacky.) Et vous pouvez le laisser sortir de la classe d'exception, auquel cas toutes les exceptions qui héritent deStandardError
sera pris. (Veuillez noter que cela ne signifie pas que tous exceptions sont pris, car il y a des exceptions qui sont des instances deException
mais pasStandardError
. Pour la plupart très grave exceptions qui compromettent l'intégrité du programme, telles queSystemStackError
,NoMemoryError
,SecurityError
,NotImplementedError
,LoadError
,SyntaxError
,ScriptError
,Interrupt
,SignalException
ouSystemExit
.)Certains blocs de la forme implicite blocs d'exception. Par exemple, les définitions de méthode sont implicitement aussi des blocs d'exception, donc au lieu d'écrire
vous écrire juste
ou
La même chose s'applique à
class
définitions etmodule
définitions.Toutefois, dans le cas précis que vous me demandez, il n'y a en fait un bien meilleur idiome. En général, lorsque vous travaillez avec des ressources dont vous avez besoin pour nettoyer à la fin, vous ne faites que par le passage d'un bloc à une méthode qui fait tout le nettoyage pour vous. Il est semblable à un
using
bloc en C#, à l'exception que Ruby est en fait assez puissant pour que vous n'avez pas à attendre pour les grands prêtres de Microsoft à descendre de la montagne et ont gracieusement accepté de changer leur compilateur pour vous. En Ruby, vous pouvez simplement mettre en œuvre vous-même:Et vous savez quoi: c'est déjà disponibles dans la bibliothèque de base comme
File.open
. Mais c'est une tendance générale que vous pouvez utiliser dans votre propre code ainsi, pour la mise en œuvre de toute forme de ressource de nettoyage (à lausing
en C#) ou les transactions ou ce que vous pourriez penser.Le seul cas où cela ne fonctionne pas, si l'acquisition et de libérer les ressources sont réparties sur les différentes parties du programme. Mais si c'est localisé, dans votre exemple, vous pouvez facilement utiliser ces ressources blocs.
BTW: moderne C#,
using
est en fait superflue, parce que vous pouvez mettre en œuvre Ruby-style de ressources blocs-vous:ensure
instructions sont exécutées dernier, ils ne sont pas la valeur de retour.begin ... rescue Exception => e ... puts e.message; puts e.backtrace.inspect ... end
.ensure
est appelé à n'importe quoi."using
. Leopen
méthode doit encore faire le nettoyage. L'exemple ne vient cette détaillé (et pas 100% à l'épreuve des balles) ainsi, au lieu d'utiliser leusing
de sténographie. Je recommandeusing
chaque fois que possible au lieu detry-finally
.using
est "superflu:" son but est d'être une jolie manière de l'écriture du try - finally bloc que vous avez écrit.using
comme une méthode de bibliothèque, et n'ont pas besoin d'une construction du langage. En fait, en C♯ 3, vous peut écrireusing
comme une méthode de bibliothèque en prenant unAction<T>
ouFunc<T, R>
(oùT : IDisposable
) et la centralisation de latry
/catch
en un seul endroit dans la bibliothèque. J'ai écrit un spécifiqueFile.open
méthode, mais vous pouvez écrire un génériqueObject.using
plutôt la méthode, qui prend la ressource comme un argument.Pour info, même si une exception est relancé dans la
rescue
section, leensure
bloc sera exécuté avant l'exécution du code continue à la prochaine gestionnaire d'exception. Par exemple:Si vous voulez vous assurer qu'un fichier est fermé, vous devez utiliser la forme de bloc de
File.open
:Oui,
ensure
est appelé dans toutes les circonstances. Pour plus d'informations, voir "Les Exceptions, Attraper et Lancer" de la Programmation Ruby livre et de la recherche pour "assurer".Oui,
ensure
permet d'exécuter à chaque fois, de sorte que vous n'avez pas besoin de lafile.close
dans lebegin
bloc.Par ailleurs, un bon moyen de tester est de le faire:
Vous pouvez tester pour voir si "=========à l'intérieur de veiller à bloc" sera imprimé quand il y a une exception.
Ensuite, vous pouvez mettre en commentaire l'instruction qui génère l'erreur et de voir si le
ensure
instruction est exécutée par voir si quelque chose est imprimé.C'est pourquoi nous avons besoin de
ensure
:Oui,
ensure
commefinally
garantit que le bloc sera exécuté. Ceci est très utile pour s'assurer que les ressources critiques sont protégés par exemple, la fermeture d'un descripteur de fichier en cas d'erreur, ou la libération d'un mutex.File.open
partie n'est PAS à l'intérieur de la commencer-veiller à ce bloc. Seulementfile.close
est, mais il n'est pas suffisant.