在Clojure中尝试使用资源

时间:2017-10-10 15:54:08

标签: clojure try-with-resources

Clojure是否具有Java try-with-resources构造的等价物?

如果没有,在Clojure代码中处理这个习惯用法的正常方法是什么?

用于安全打开和关闭资源的Java-7之前的习惯用语非常冗长,以至于它们实际上增加了对该语言的try-with-resources的支持。我觉得很难在标准的Clojure库中找到这个用例的宏。

基于Clojure的主流项目存储库的一个示例 - 显示如何在实践中处理此问题 - 将非常有用。

2 个答案:

答案 0 :(得分:9)

您可以使用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 - finally创建的.close()方法。

答案 1 :(得分:0)

你可以做一些更接近java的事情,在with-open之上构建一些宏。它看起来像这样:

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

因此您可以在绑定旁边传递其他条款。

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

但它仍然是一个固执己见的解决方案。