在clojure中将java方法名称作为函数arg

时间:2009-11-12 01:18:53

标签: function clojure macros

所有

我想创建一个函数,该函数接受表示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被称为''的第二个arg。函数而不是绑定到m?

的值

2 - ;我怎么才能真正做我想做的事?

3 个答案:

答案 0 :(得分:12)

它不起作用,因为.special form并且有特殊的评估规则。普通函数调用评估它们的参数,但.不评估method-name参数。

要使其正常工作,请使用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

答案 1 :(得分:2)

问题是方法调用是在JVM字节码中硬连线的。正如Brian所说,eval将起作用,因为它每次调用时都会编译代码。但请远离eval。它有它的用途,但这个不是其中之一。

最好的方法是做你想要的就是使用反射。或者如果可能的话,使用Brian展示的宏。反思可以通过以下方式完成:

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

虽然没有真正测试过......

答案 2 :(得分:0)

宏Brian暗示已经存在,并且被称为memfn,用于“成员函数”。

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