4

我有一个记录/类序列,并且我map在该序列上使用new并期望获得这些记录/类的一系列实例。我知道这new是一种特殊的形式,但我期待 Clojure 在这种情况下做正确的事情。

但这不起作用:

(map new [SomeClass1 SomeClass2 SomeClass3])

这个也不行。

(map #(new %) [SomeClass1 SomeClass2 SomeClass3])

类似的代码适用于Factor

{ SomeClass1 SomeClass2 SomeClass3 } [ new ] map

在 Clojure 中执行此操作的正确方法是什么?(我希望它不会涉及Class.newInstance丑陋。)

编辑:

以下工作,但可能比必要的要慢。(我不确定。我会很感激这方面的一些信息。)

(map #(eval `(new ~%)) [SomeClass1 SomeClass2 SomeClass3])

我也在寻找更优雅的东西。

4

2 回答 2

3

因为特殊形式很好......特别它们不是一流的,也不像正确的函数那样组成,你可以用 eval 和宏来解决这个问题:

使用 eval 的解决方案:

(defn fnew [c] (eval `(new ~c))) 
hello.core> (map fnew ['Exception 'java.lang.String])
(#<Exception java.lang.Exception> "")

以及一个将参数传递给构造函数的版本:

(defn fnew [c] (eval `(new ~@c))) 

hello.core> (map fnew ['(Exception) '(java.lang.String "I am a contructor argument")])
(#<Exception java.lang.Exception> "I am a contructor argument")

(map fnew [ [Exception] [(class "foo") "I am a contructor argument"]])
(#<Exception java.lang.Exception> "I am a contructor argument")

这是一个宏示例

hello.core> (defmacro newify [classes] (apply vector (for [c classes] `(new ~c))))
#'hello.core/newify

hello.core> (macroexpand '(newify [java.lang.String Exception]))
[(new java.lang.String) (new Exception)]

hello.core>  (newify [java.lang.String Exception])
["" #<Exception java.lang.Exception>]

宏版本可能更有效,而 eval 版本更灵活。

于 2012-06-01T20:34:35.303 回答
1

作为new一种特殊形式,使其像一流一样工作的解决方案之一是使用 clojure 低级调用,例如:

(map #(clojure.lang.Reflector/invokeConstructor %1 (into-array [])) [String])

这可能会导致反射的性能问题,因此基于宏的解决方案比这更受欢迎。

于 2012-06-02T08:52:45.237 回答