自动关闭行为已由解决
with-open
宏。参见实施
here
. 这里有一个公式(我认为)可以满足你的要求。
(defmacro safe
([body]
`(try ~body
(catch Exception e#
(str "caught exception: " e#))))
([bindings & body]
`(try
(with-open ~bindings
~@body)
(catch Exception e#
(str "caught exception: " e#)))))
示例用法:
(safe (/ 1 nil))
;;=> "caught exception: java.lang.NullPointerException"
(safe [s (clojure.java.io/reader "file.txt")]
(prn (.read s)))
;;=> "caught exception: java.io.FileNotFoundException: file.txt (No such file or directory)"
(spit "file.txt" "contents here")
(safe [s (clojure.java.io/reader "file.txt")]
(.read s))
;;=> 99
然而
-
失败时返回字符串令人困惑,因为如果
预期
值也是字符串?那么,您如何知道您的评估是成功还是失败?也许您只想打印/记录异常并返回nil?(在这种情况下,考虑更换
str
具有
println
在您的
catch
块。)
-
有两个数的
safe
(一种仅采用一种身体形态,另一种则采用装订
close
d
和
身体形态)纠缠着可以说应该分开的担忧。
打开时
已经存在了,当我们可以重用它时,我们不应该再进行改造。
此版本的
安全
可以采用任意数量的形式,而不是仅采用一种形式,因此现在更加灵活。
(defmacro safe
[& body]
`(try ~@body
(catch Exception e#
(println "caught exception:" (.getMessage e#)))))
我们可以很容易地使用
打开时
在内部
安全
要获得您想要的行为:
(safe
(prn (/ 1 2)) ;; prints 1/2
(with-open [s (clojure.java.io/reader "not_a_file.txt")]
(.read s))) ;; fails, prints exception
(safe
(with-open [s (clojure.java.io/reader "file.txt")]
(char (.read s)))) ;; returns the first char from file we `spit` above
;;=> \c