Pau*_*ers 6 constructor clojure new-operator
我知道我可以在Clojure中实例化这样的Java类:
(new Classname args*)
Run Code Online (Sandbox Code Playgroud)
假设我已经提交了构造函数使用的args 列表.那我怎么实例化这个类呢?我不能使用,apply因为new不是一个功能.
有两种基本方法:
反射:
(clojure.lang.Reflector/invokeConstructor Klass (to-array [arg ...]))
Run Code Online (Sandbox Code Playgroud)
慢,但完全动态.
事先解压缩参数:
(let [[arg1 arg2 ...] args]
(Klass. arg1 arg2 ...))
Run Code Online (Sandbox Code Playgroud)
((Klass. ...)是惯用的写作方式(new Klass ...);它在宏扩展时转换为后一种形式.)
如果编译器可以推断出将使用哪个构造函数,那么这将更快(您可能需要提供适当的类型提示 - 用于(set! *warn-on-reflection* true)查看您是否正确).
当然,第二种方法略显笨拙.如果您希望Klass在代码中的许多位置构建大量实例,则可以编写适当的工厂函数.如果您希望以这种方式处理许多类,则可以抽象出定义工厂函数的过程:
(defmacro deffactory [fname klass arg-types]
(let [params (map (fn [t]
(with-meta (gensym) {:tag t}))
arg-types)]
`(defn ~(with-meta fname {:tag klass}) ~(vec params)
(new ~klass ~@params))))
Run Code Online (Sandbox Code Playgroud)
最后,如果定义工厂函数本身的过程需要完全动态,你可以做一些像Chouser的第二个方法来解决这个问题:定义一个函数而不是一个宏,并让它eval像(defn ...)上面的语法引用形式(语法引用) =在它前面有反引号;我不确定如何在SO帖子中包含文字反引号),除了你想要使用fn而不是defn可能跳过fname.对编译器的调用将是昂贵的,但返回的函数将执行任何Clojure函数; 请参阅Chouser的上述答案进行稍长时间的讨论.
为了完整起见,如果您使用Clojure 1.3或更高版本并且所涉及的Java类实际上是Clojure记录,那么将在名称下创建位置工厂函数->RecordName.
| 归档时间: |
|
| 查看次数: |
956 次 |
| 最近记录: |