2017-10-10 15 views
3

ClojureにはJavaのtry-with-resources構造と同等のものがありますか?Clojureでリソースを試してみよう

そうでない場合、Clojureコードでこのイディオムを処理する通常の方法は何ですか?

リソースを安全に開いたり閉じたりするためのJava-7以前のイディオムは、実際にはリソースに対するtry-with-resourcesのサポートが追加されているほど冗長です。標準のClojureライブラリでこのユースケースのマクロを見つけることができないのは私にとっては奇妙なことです。

メインストリームのClojureベースのプロジェクトリポジトリの例(この問題がどのように実際に処理されるかを示す)は非常に役に立ちます。

答えて

6

with-openを使用してリソースをシンボルにバインドし、制御フローがブロックを離れるとリソースが閉じられることを確認できます。

次の例は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))))) 

これを次のように展開されます:

(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)))) 

あなたはletブロックがtryで作成されていることがわかります - コール.close()方法にfinally

+0

これは意味があります。私はまだ開いているまたはリソースを使用している間にスローされた例外をキャッチするために、 'with-open'の周りにもう1つの' try'フォームを追加する必要がありますが、try/catchロジックとは別にオープン/悪いこと。私はJavaのコンストラクタと1対1の同等性を期待していましたが、実際にはそれを期待する必要はありません。 – DaoWen

+0

あなたは '(try ...)'ブロックの中に '(Exception e ... catch ')と'(finally(.close r)) 'を持つことができますが、' with-resource'マクロはそれはあなたがそれをあなた自身で書く必要があるので、デフォルトでです。 – erdos

+0

@DaoWen 1:1の等価です。 'try(Foo x = bar()){...}'は 'bar()'の呼び出し中に発生した例外を処理しません。どうした?スコープに '.close()'を呼び出す有効な 'x'はありません。 – amalloy

0

Javaの近くでは、with-openの上にマクロを作成することができます。

(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]))) 

このように、バインディングの横に追加の句を渡すことができます。

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

は、単純なwith-openに展開:

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

追加条項はのtry-catchでラップにつながるながら:

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

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

しかし、まだに展開しますそれはかなりの意見ですソリューション。

関連する問題