所有
我想创建一个函数,该函数接受表示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 - ;我怎么才能真正做我想做的事?
答案 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