2017-10-10 1 views
3

Est-ce que Clojure a un équivalent de construction try-with-resources de Java? Si ce n'est pas le cas, quelle est la manière normale de gérer ce langage dans le code de Clojure?Try-with-resources dans Clojure

L'idiome pré-Java-7 pour l'ouverture et la fermeture de ressources en toute sécurité est suffisamment détaillé pour qu'ils ajoutent un support pour les ressources d'essai au langage. Il me semble étrange que je ne trouve pas de macro pour ce cas d'utilisation dans la bibliothèque Clojure standard.

Un exemple pour un référentiel de projet basé sur Clojure, qui montre comment ce problème est traité dans la pratique, serait très utile.

Répondre

6

Vous pouvez utiliser with-open pour lier une ressource à un symbole et vous assurer que la ressource est fermée une fois que le flux de contrôle a quitté le bloc.

L'exemple suivant provient de clojuredocs.

(with-open [r (clojure.java.io/input-stream "myfile.txt")] 
    (loop [c (.read r)] 
     (when (not= c -1) 
     (print (char c)) 
     (recur (.read r))))) 

Ce sera étendu à ce qui suit:

(let [r (clojure.java.io/input-stream "myfile.txt")] 
    (try 
    (loop [c (.read r)] 
     (when (not= c -1) 
     (print (char c)) 
     (recur (.read r)))) 
    (finally (.close r)))) 

Vous pouvez voir qu'un bloc let est créé avec un try - finally la méthode appel .close().

+0

OK, c'est logique. Je devrais encore ajouter un autre formulaire 'try' autour du' with-open' pour attraper les exceptions levées lors de l'ouverture ou de l'utilisation des ressources - mais je suppose que la manipulation de l'automation open/close séparément de la logique try/catch n'est pas une mauvaise chose. Je m'attendais juste à une équivalence 1: 1 avec la construction Java - mais il n'y a vraiment aucune raison que j'aurais dû m'y attendre. – DaoWen

+0

vous pouvez avoir à la fois un '(catch Exception e ...)' et un '(finally (.close r))' dans un bloc '(try ...)' mais la macro 'with-resource' ne supporte pas Par défaut, vous devrez l'écrire vous-même. – erdos

+0

@DaoWen Il s'agit d'une équivalence 1: 1. 'try (Foo x = bar()) {...}' ne gère aucune exception rencontrée lors de l'appel de 'bar()'. Comment pourrait-il? Il n'y a pas de 'x' valide pour appeler' .close() '. – amalloy

0

vous pouvez faire quelque chose de plus proche de Java, en faisant de la macro au-dessus de with-open. Il pourrait ressembler à ceci:

(defmacro with-open+ [[var-name resource & clauses] & body] 
    (if (seq clauses) 
    `(try (with-open [~var-name ~resource] [email protected]) 
      [email protected]) 
    `(with-open [~var-name ~resource] [email protected]))) 

de sorte que vous pouvez passer des clauses supplémentaires à côté de la liaison.

(with-open+ [x 111] 
    (println "body")) 

étend à de simples with-open:

(let* 
    [x 111] 
    (try (do (println "body")) (finally (. x clojure.core/close)))) 

tandis que des clauses supplémentaires conduisent à envelopper le dans try-catch:

(with-open+ [x 111 
      (catch RuntimeException ex (println ex)) 
      (finally (println "finally!"))] 
    (println "body")) 

étend à

(try 
    (let* 
    [x 111] 
    (try (do (println "body")) (finally (. x clojure.core/close)))) 
    (catch RuntimeException ex (println ex)) 
    (finally (println "finally!"))) 

Mais encore c'est plutôt un avis solution ed.