2013-10-08 17 views
4

假設我定義這樣Clojure的功能:的Clojure:進口Java類動態

(defn print-this [this] (println "print this: " this)) 

如果我使用的功能在REPL:

(print-this that) 

我將結束:

print this: that 
nil 
輸出爲

現在,如果我做出這樣的定義:

(defn import-by-name [name] (import (some.package.value name))) 

,並在REPL使用功能:

(import-by-name "SomeClassName") 

我得到

java.lang.ClassNotFoundException: some.package.value.name (NO_SOURCE_FILE:0) 

在那裏我會想到 「名」 是取而代之的是「SomeClassName」。如果我輸入:

(import (some.package.value SomeClassName)) 

一切按預期工作。

爲什麼在上面的導入按名稱函數中沒有解釋[name]? 是否有可能從一個變量值動態地導入一個java類?如果是這樣如何?謝謝!

回答

4

import是一個宏,所以你傳遞給它的任何符號都將從字面上看出來。

(macroexpand '(import (some.package.value name))) 

;; => (do (clojure.core/import* "some.package.value.name")) 

字面

對於字符串常量,並推而廣集文字,你可以使用宏來完成你所描述的。

(defmacro import-by-name [name] `(import '[some.package.value ~name])) 

(import-by-name "ClassName") ;; => nil 

瓦爾

對於從VAR導入類,你必須開始浸入命名空間的內部。

(defn import-by-name [n] 
    (.importClass (the-ns *ns*) 
       (clojure.lang.RT/classForName (str "some.package.value." n)))) 

有可能是一個更乾淨的方式,我會更新這個答案,如果我找到一個。

+0

它的工作!謝謝! – Sebastien

+0

請注意,有限制。傳遞一個字符串可以工作,但是傳遞一個var只會附加符號。我不確定你到底在做什麼。 – Jared314

+0

有無論如何用var來做類似的事情嗎?目標是將clojure代碼與來自相當複雜的xsd的大型xjc生成的java庫進行接口。 – Sebastien