Clojure可选定义
在Python中,我可以执行以下操作:Clojure可选定义,clojure,Clojure,在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做同样的事情吗? 我已尝试下一步,但失败(
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做同样的事情吗?
我已尝试下一步,但失败(例如,仍然需要导入):
代码抛出
IllegalArgumentException:即使LongAdder
本身不可用,也无法解析classname:LongAdder
。正如@amalloy在注释中指出的那样,时内的代码不编译。我不确定是否有办法重新编写代码,以便编译。但是,可以完全避免编译它。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的博客文章“”和.的启发,因此您启动了一个repl,然后键入(import'java.util.concurrent.NotAClass)
,然后得到了一个IllegalArgumentException
?你的代码对我来说工作正常。ClassNotFoundException
被捕获。另一方面,您的交换代码>表单最好表示为:(reset!long adder available true)
,您也可以在时将更简洁地表示为:(当@long adder available…
时),并在try
和when
下,你不需要一个do
@Josh我不同意你的评估,它按预期工作。重要的不是运行时由import
表达式引发的ClassNotFoundException,而是编译时由when
中的代码引发的ClassNotFoundException,无论它是否实际运行,它都会被编译。@amalloy Oops!当我运行这个示例时,我完全忘记了将类的用法放在When
块中。谢谢你的接球!你的结论是海报想要做的是不可能的吗?不是不可能的,但它是粗俗的、艰难的,而且通常不像Clojure那样做。你基本上必须使用反射,而不是通常引用类。我在考虑宏,但我认为有更好的方法。非常感谢。
(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)))