gpt4 book ai didi

clojure - cljc 宏中的错误处理

转载 作者:行者123 更新时间:2023-12-02 21:03:40 24 4
gpt4 key购买 nike

我发现定义一个宏来在 cljcljs 中进行错误处理非常棘手。我以为这只是将 Exceptionjs/Error 交换的简单问题,但事实证明比这更复杂。

首先,我尝试了这个:

(defmacro my-macro
[& forms]
`(try
~@forms
(catch #?(:clj Exception :cljs js/Error) e#
,,,)))

但这每次都会产生异常。我很快意识到问题是在编译我的 cljs 文件期间调用了宏,这发生在 clj 环境中。因此,我必须让宏返回一个在运行时解析为正确的异常类的形式。我试过这个:

(def exception-class
#?(:clj Exception :cljs js/Error))

(defmacro my-macro
[& forms]
`(try
~@forms
(catch exception-class e#
,,,)))

现在它可以在 cljs 中运行,但不能在 clj 中运行!经过一些实验,我发现 JVM Clojure(显然)不允许您间接引用异常类。您必须直接通过名称引用Exception

最后,我决定这样做:

(def fake-java
#?(:cljs (clj->js {:lang {:Exception js/Error}})))

(defmacro my-macro
[& forms]
`(let [~'java fake-java]
(try
~@forms
(catch Exception e#
,,,))))

Exception 扩展为 java.lang.Exception,现在在 clj 中都在运行时解析为正确的异常类cljs

我的问题是,有更好的方法吗?为什么 JVM Clojure 不允许间接引用异常类,但 ClojureScript 却允许?

更新

在 ClojureMoSTLy 的帮助下,我像这样重构了宏,并且它有效:

(defmacro my-macro
[& forms]
`(try
~@forms
(catch ~(if (:ns &env) 'js/Error 'Exception) e#
,,,)))

最佳答案

执行此操作的常见方法是 check for the :ns keydefmacro 中的特殊 &env 绑定(bind)中。 Copied from plumatic/schema :

(defn cljs-env?
"Take the &env from a macro, and tell whether we are expanding into cljs."
[env]
(boolean (:ns env)))

(defmacro try-catchall
"A cross-platform variant of try-catch that catches all exceptions.
Does not (yet) support finally, and does not need or want an exception class."
[& body]
(let [try-body (butlast body)
[catch sym & catch-body :as catch-form] (last body)]
(assert (= catch 'catch))
(assert (symbol? sym))
(if (cljs-env? &env)
`(try ~@try-body (~'catch js/Object ~sym ~@catch-body))
`(try ~@try-body (~'catch Throwable ~sym ~@catch-body)))))

用法:

(macros/try-catchall (f)  (catch e# ::exception))

关于clojure - cljc 宏中的错误处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41516492/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com