在Python中,我可以做类似的事情:
fast_thing_available = True
try:
import fast_thing
except ImportError:
fast_thing_available = False
# snip
if fast_thing_available:
default = fast_thing
else:
default = slow_thing
在Clojure中可以做同样的事情吗? 我接下来尝试了,但失败了(例如仍需要导入):
(ns sample.ns)
(def ^:private long-adder-available (atom false))
(try
(do
(import 'java.util.concurrent.atomic.LongAdder)
(swap! long-adder-available (constantly true)))
(catch ClassNotFoundException e ()))
(when (true? @long-adder-available)
(do
; Here I'm using LongAdder itself
))
即使IllegalArgumentException: unable to resolve classname: LongAdder
本身不可用,代码也会引发LongAdder
。
答案 0 :(得分:1)
正如@amalloy在评论中指出的那样,when
中的代码无法编译。我不确定是否有办法重新编写代码以便编译。但是,可以避免完全编译它。 Clojure宏可用于从编译中排除代码。
宏可以尝试导入类,并且只有在成功使用类发出代码时才会导入。有更简单的方法可以检查类路径中是否存在类,但在编译时调用import
很重要。这样代码可以使用简单的类名(如LongAdder
)。
当应用于此问题时,解决方案可能类似于下面的示例。调用import
的代码对eval
等有点难看,但很难将非文字参数传递给import
。如果此代码不需要通用,则可以对类名进行硬编码,并简化其他一些操作。
(ns sample.core)
(defmacro defn-if-class
"If clazz is successfully imported, emits (defn name args then)
Emits (defn name args else) otherwise."
[clazz name args then else]
(if (try (eval `(import ~clazz)) true (catch Exception e nil))
`(defn ~name ~args ~then)
`(defn ~name ~args ~else)))
(defn-if-class java.util.concurrent.atomic.LongAdder
foo []
;; if class exists
(doto (LongAdder.)
(. increment)
(. sum))
;; else
"fallback logic in case the class is not in classpath")
(defn -main [& args]
(println (foo)))
我应该提一下,答案很大程度上受到Jay Fields'博客文章" Clojure: Conditionally Importing"和this answer。