Clojure有没有类似于Java的try-with-resources结构的相应功能?
如果没有,Clojure代码中处理这种惯用语的常规方法是什么?
在Java 7之前,安全地打开和关闭资源的惯用语法已经足够冗长,以至于他们实际上为语言添加了对try-with-resources的支持。我觉得在标准Clojure库中找不到这个用例的宏很奇怪。
一个主流Clojure项目存储库的示例,展示了实践中如何处理这个问题,将非常有帮助。
Clojure有没有类似于Java的try-with-resources结构的相应功能?
如果没有,Clojure代码中处理这种惯用语的常规方法是什么?
在Java 7之前,安全地打开和关闭资源的惯用语法已经足够冗长,以至于他们实际上为语言添加了对try-with-resources的支持。我觉得在标准Clojure库中找不到这个用例的宏很奇怪。
一个主流Clojure项目存储库的示例,展示了实践中如何处理这个问题,将非常有帮助。
(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!")))
但仍然是一种很主观的解决方案。
with-open
周围添加另一个try
形式来捕获打开或使用资源时抛出的任何异常 - 但我想将自动打开/关闭处理与 try/catch 逻辑分开处理也不是什么坏事。我只是期望 Java 构造有一个1:1的等价物 - 但实际上没有任何理由让我期望那样。 - DaoWen(try ...)
块中,您可以同时使用(catch Exception e ...)
和(finally (.close r))
,但with-resource
宏默认不支持它,因此您需要自己编写代码。 - erdostry (Foo x = bar()) {...}
在调用bar()
时不处理任何遇到的异常。它怎么可能呢?没有有效的x
在作用域内,可以调用.close()
。 - amalloytry
表单和with-open
,而在Java中它们都是一个结构。try-with-resources
结构确实会捕获资源规范子句中抛出的异常,但你是对的,在你的例子中它不会尝试调用x
的close()
(因为在x
初始化之前就失败了)。还有一个更微妙的语义差异:当使用Java的try-with-resources
时,您将自动获得“抑制”异常的簿记。 - DaoWen