我知道我可以實例Clojure中的一個Java類像這樣的列表:中調用Java與新構造args來代替ARGS本身(Clojure中)
(new Classname args*)
想我遞的列表構造函數使用的參數。那麼我如何實例化這個類呢?我不能使用apply
,因爲new
不是函數。
我知道我可以實例Clojure中的一個Java類像這樣的列表:中調用Java與新構造args來代替ARGS本身(Clojure中)
(new Classname args*)
想我遞的列表構造函數使用的參數。那麼我如何實例化這個類呢?我不能使用apply
,因爲new
不是函數。
有兩種基本方法:
反思:
(clojure.lang.Reflector/invokeConstructor Klass (to-array [arg ...]))
慢,但完全動態的。
預先解壓縮參數:
(let [[arg1 arg2 ...] args]
(Klass. arg1 arg2 ...))
((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 [email protected]))))
最後,如果定義工廠功能的過程本身需要是完全動態的,你可以這樣做像Chouser的第二種方法this question:定義了一個函數而不是宏,並且它具有類似於上面語法引用的(defn ...)
的形式(syntax-quoted =在它前面帶有反引號;我不確定如何包含文字反引號在SO帖子中),除了你想要使用fn
而不是defn
並且可能跳過fname
。對編譯器的調用將很昂貴,但返回的函數將像任何Clojure函數一樣執行;請參閱Chouser稍後討論的上述答案。
爲了完整起見,如果您使用的是Clojure 1.3或更高版本,並且所涉及的Java類實際上是Clojure記錄,則位置工廠函數將以名稱->RecordName
創建。