将Java方法作为参数传递

时间:2015-02-20 21:32:42

标签: clojure clojure-java-interop

假设我们有一个Java类:

public class Fun {
   public int foo () {
    return 1;
   }

   public  int bar () {
      return 2;
   }

}

以下代码在Clojure中不起作用:

(defn f [method]
(. (new Fun) method)) 

(f foo)

产生预期错误(此处没有问题):

  

CompilerException java.lang.RuntimeException:无法在此上下文中解析符号:foo,编译......:

但如果我试着引用符号

(f 'foo)

它会产生不同但预期的错误:

  

IllegalArgumentException找不到匹配的字段:类com.dullesopen.srl.FunCall的方法clojure.lang.Reflector.getInstanceField(Reflector.java:271)

错误是预期的,因为根据特殊形式的文档。 (点)假设第二个参数匹配字段或方法的名称,因此它不是来自Clojure观点的实际符号。

以下方法解决了问题,但我不喜欢额外的memfn。对我来说,它表明Java方法实际上并不是Clojure中的第一类对象。

(defn f [method]
   (method (new FunCall))) 

(f (memfn foo))

所以问题是:有没有办法表明""到特殊形式.第二个参数应该以某种方式解析/评估以获得方法名称?或者也许还有另外一个类似dot的特殊但第二个参数已解决?

1 个答案:

答案 0 :(得分:3)

你的理解是正确的, java方法实际上不是clojure中的第一类公民。你不能独立于它的类传递方法。我能想到的最接近的是传递了解类和方法的函数,或者使用宏来为每个类构建对方法的调用。如果你不喜欢上面的方法(这看起来对我很好),那么 这可以直接使用宏来完成,但我个人更喜欢你的方法:

user> (defmacro f [method]
        `(. (String. "asdf") ~method))
#'user/f
user> (f hashCode)
3003444

PS:memfn被函数文字语法取代。它很少使用。