2009-11-12 15 views
4

所有,以Java方法的名稱作爲功能ARG Clojure中

我想創建一個函數,它代表Java方法的象徵,它適用於一些對象:

(user=> (defn f [m] (. "foo" (m))) 

當我執行此,我得到的結果從非常不同的我所期望

user=> (f 'getClass) 
java.lang.IllegalArgumentException: No matching method found: m for class java.lang.String (NO_SOURCE_FILE:0) 

2個問題:

1>爲什麼符號m被稱爲'。'的第二個參數。函數而不是綁定到m的值?

2>我該怎麼做我想做的事?

回答

12

這不起作用,因爲.special form並且有特殊的評估規則。正常函數調用評估它們的參數,但.不計算方法名稱參數。

要使其工作,請使用eval或將您的功能更改爲宏。

user=> (defmacro foo [o m] `(. ~o ~m)) 
#'user/foo 
user=> (foo 123 toString) 
"123" 
user=> (defn bar [o m] (eval `(. ~o ~m))) 
#'user/bar 
user=> (bar 123 'toString) 
"123" 

通常不推薦使用eval

+0

宏上的+1。不需要評估。 – 2009-11-12 02:10:47

2

問題是方法調用在JVM字節碼中是硬連線的。正如Brian所說的,eval可以工作,因爲它每次調用時都會編譯代碼。但遠離eval。它有它的用途,但這不是其中之一。

最好的方法是做你想做的就是使用反射。或者如果可能的話,使用Brian展示的宏。反射可以通過做:

(defn f 
    [m & args] 
    (clojure.lang.Reflector/invokeInstanceMethod obj m (into-array Object args)))

沒有真正測試過,但...

0

宏布賴恩暗示已經存在,被稱爲memfn,對於「成員函數」。

user> ((memfn length) "test") 
4