用于写入try块的Clojure宏 问题
我正在尝试使用Clojure定义一个宏,其工作原理与java中的try类似 它应该能够有一个绑定表单,例如[variable value],可以绑定到closable的实例 Java中的示例 在这段代码中,套接字“s”被自动关闭,就好像有一个明确的finally子句一样用于写入try块的Clojure宏 问题,clojure,macros,try-catch,Clojure,Macros,Try Catch,我正在尝试使用Clojure定义一个宏,其工作原理与java中的try类似 它应该能够有一个绑定表单,例如[variable value],可以绑定到closable的实例 Java中的示例 在这段代码中,套接字“s”被自动关闭,就好像有一个明确的finally子句一样 finally { if (s != null) s.close(); } 尝试解决方案 输入和输出示例 我不知道我可以在这个宏中调整什么,但我不能让它不返回错误 更新 这个解决方案几乎奏效 (defmacro safe
finally {
if (s != null) s.close();
}
尝试解决方案
输入和输出示例
我不知道我可以在这个宏中调整什么,但我不能让它不返回错误
更新
这个解决方案几乎奏效
(defmacro safe
([[s NewS] expression]
`(try
(let [~s ~NewS] ~expression) (catch Exception e# (str "caught exception: " (.getMessage e#)))
))
([expression]
`(try
~expression (catch Exception e# (str "caught exception: " (.getMessage e#)))
))
)
但是下面的测试失败了
(defn-main)
“我还没有做很多……还没有。”
[&args]
(导入java.io.FileReader java.io.File)
(def v(safe[s(FileReader.(File.File.txt”))](.reads)))
(打印版本五)
)
自动关闭行为已通过使用open宏解决。参见实现。这里有一个公式(我认为)能满足你的要求
(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
然而
safe
(一个只采用一种主体形式,另一个采用绑定为close
d和主体形式)的算术运算会纠缠应该分开的关注点<带有open的code>已经存在,当我们可以重用它时,我们不应该重新创建它safe
可以采用任意数量的表单,而不仅仅是一个表单,因此它现在更加灵活
(defmacro safe
[& body]
`(try ~@body
(catch Exception e#
(println "caught exception:" (.getMessage e#)))))
我们可以在safe
中轻松使用和open
来获得您想要的行为:
(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
我想你可以用这个。我真的不明白我的主要缺点是什么。即使在使用open时,我也会遇到类似的错误
(defmacro safe[&s newS]expression](如果s
(let[~s~newS]))(使用open~newS&~expression))(defn-main[&args](def v(safe(/10)))
您是否检查了macroexpand
为您的宏提供的内容?这里的代码格式不好,因此很难阅读。此外,Clojure使用分号作为注释,而不是普通的哈希。另外,请思考一下s
和newS
对于您的除法为0的示例是什么。
user$ lein run
caught exception: file.txt (No such file or directory)
user$ cat file.txt
teast
(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
(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