在 Clojure 中试用资源
Try-with-resources in Clojure
Clojure 是否具有 Java 的 try-with-resources 构造的等效项?
如果不是,在 Clojure 代码中处理这个习语的正常方法是什么?
Java-7 之前用于安全打开和关闭资源的习语非常冗长,以至于他们实际上为语言添加了对 try-with-resources 的支持。我在标准 Clojure 库中找不到这个用例的宏,这对我来说似乎很奇怪。
一个主流的基于 Clojure 的项目存储库的例子——展示这个问题在实践中是如何处理的——会很有帮助。
您可以使用 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()
方法创建的。
你可以做一些更接近 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!")))
但这仍然是一个固执己见的解决方案。
Clojure 是否具有 Java 的 try-with-resources 构造的等效项?
如果不是,在 Clojure 代码中处理这个习语的正常方法是什么?
Java-7 之前用于安全打开和关闭资源的习语非常冗长,以至于他们实际上为语言添加了对 try-with-resources 的支持。我在标准 Clojure 库中找不到这个用例的宏,这对我来说似乎很奇怪。
一个主流的基于 Clojure 的项目存储库的例子——展示这个问题在实践中是如何处理的——会很有帮助。
您可以使用 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()
方法创建的。
你可以做一些更接近 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!")))
但这仍然是一个固执己见的解决方案。