如果您不能確定類在編譯時(可能在編程宏),你需要求助於使用反射。這將和eval在嘗試編譯代碼時所做的一樣。見clojure.lang.Reflector/invokeStaticMethod
:https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Reflector.java#L198
(import 'clojure.lang.Reflector)
;; Here, you can pass *any string you have at runtime*
(Reflector/invokeStaticMethod Integer "parseInt" (into-array ["1"]))
這可以以任意方式在運行時使用,因爲它不是一個宏或一種特殊形式。例如,該方法的名稱可以由用戶通過GUI或雖然在運行時的插座給出。
如果在編譯時類的名稱,你可以使用宏作爲薩科建議。然而,這是不必要的構建代碼看起來像(Integer/parseInt "1")
,因爲它是更基本的(和宏觀型).
特殊形式只是語法糖:(. Integer parseInt "1")
。
;; Here, the method name needs to be a *string literal*
(defmacro static-call
"Takes a Class object, a string naming a static method of it
and invokes the static method with the name on the class with
args as the arguments."
[class method & args]
`(. ~class ~(symbol method) [email protected]))
但是,這個宏唯一的「真正的工作」是將字符串轉換爲符號。您可能只需在外部宏中使用.
特殊格式(即以某種方式獲取方法名稱的格式,例如通過獲取作爲參數傳遞的格式,或通過從var或配置文件讀取它們)。
;; Use ordinary Clojure functions to construct this
(def the-static-methods {:foo ["Integer" "parseInt"], :bar ["Long" "parseLong"]})
;; Macros have access to all previously defined values
(defmacro generate-defns []
(cons `do (for [[name-keyword [class-string method-string]] the-static-methods]
`(defn ~(symbol (name name-keyword)) [x#]
(. ~(symbol class-string) ~(symbol method-string) x#)))))
(generate-defns)
你能解釋一下你爲什麼要這樣做嗎? – 2011-04-28 09:43:45
我不得不應對設計不佳的Java API,其中沒有方法的基本接口被其他幾個接口擴展,每個接口都提供一種方法。這些方法意味着通過具體實現註冊爲回調,這是通過反射(例如'Registry.registerCallback(ImplementedInterface/CONDITION,concreteInstance,「callbackMethodName」)「)完成的。我想隱藏所有的犛牛刮背後更溫柔的Clojure API代碼,因此我需要動態綁定到接口並使用反射來執行回調註冊。 – skuro 2011-04-28 10:02:57
eval方法有一個鬼鬼祟祟的缺點:eval不能在本地範圍中使用變量;就好像它是在頂層執行的一樣。因此,(讓[x 1](eval'(inc x)))導致「無法解析符號:x」錯誤。 – raek 2011-04-29 09:51:17