Clojure有相当于Java的try-with-resources构造吗?尝试在Clojure中使用资源
如果不是,那么在Clojure代码中处理这种习惯用法的正常方法是什么?
用于安全打开和关闭资源的Java-7以前的习惯用法是非常详细的,它们实际上增加了对语言尝试资源的支持。对我来说,在标准的Clojure库中我找不到这个用例的宏是很奇怪的。
基于Clojure的主流项目存储库的一个例子 - 显示如何在实践中处理这个问题 - 将是非常有用的。
Clojure有相当于Java的try-with-resources构造吗?尝试在Clojure中使用资源
如果不是,那么在Clojure代码中处理这种习惯用法的正常方法是什么?
用于安全打开和关闭资源的Java-7以前的习惯用法是非常详细的,它们实际上增加了对语言尝试资源的支持。对我来说,在标准的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] [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!")))
但仍这是相当意见ed解决方案。
好的,这是有道理的。我仍然必须在'with-open'周围添加另一个'try'形式来捕获在打开或使用资源时抛出的任何异常 - 但是我猜想独立于try/catch逻辑处理开放/关闭自动化不是一件坏事。我只是期望与Java构造有1:1的等价关系,但我真的没有理由期待这一点。 – DaoWen
你可以在一个'(try ...)'块中有一个'(catch Exception ...)'和一个'(finally(.close r))',但是'with-resource'宏不支持它默认,所以你将不得不自己写。 – erdos
@DaoWen它是1:1等价。 'try(Foo x = bar()){...}'不处理调用'bar()'时遇到的任何异常。它怎么可能?在作用域中没有有效的'x'来调用'.close()'。 – amalloy