在Clojure中扩展Java接口的错误

时间:2016-01-20 14:18:47

标签: clojure

我有一个基本的Java接口定义如下:

public interface Action {
    void execute(Metadata var1, Parameter var2);
}

我试图在Clojure中扩展它,但不断出错。将类导入我的命名空间后,我尝试使用reify,如下所示:

(defn action [action-fn]
  (reify Action
    (execute [metadata parameter] (action-fn metadata parameter))))

但是会抛出编译器非法参数异常:

CompilerException java.lang.IllegalArgumentException: Can't define method not in interfaces: execute

接下来我尝试使用proxy

(defn action [action-fn]
  (proxy [Action] []
    (execute [metadata parameter] (action-fn metadata parameter))))

编译成功,我的编辑器(IntelliJ + Cursive)通过边框修饰导航到接口定义,但尝试在生成代理上调用execute失败:

(.execute (action (fn [_ _] "Test action")))

抛出以下内容:

IllegalArgumentException No matching field found: execute for class

最后我尝试使用deftype如下:

(deftype cljAction [action-fn]
  Action
  (execute [metadata parameter] (action-fn metadata parameter)))

抛出与reify相同的编译器错误,例如:

CompilerException java.lang.IllegalArgumentException: Can't define method not in interfaces: execute

通过各种博客文章和SO答案进行搜索似乎表明它存在争议的问题,但我不确定如何解决它。我做错了什么?

2 个答案:

答案 0 :(得分:5)

您缺少该函数的this引用。所以你想要的是:

(defn action [action-fn]
  (reify Action
    (execute [this metadata parameter] (action-fn metadata parameter))))

显然,因为您没有使用它,您可以将其称为_或您认为最有意义的任何内容。当你调用你想要的功能时:

(.execute (action action-fn) metadata parameter)

这与您实施协议时略有不同。有关详细信息,请参阅https://clojuredocs.org/clojure.core/definterface

答案 1 :(得分:2)

ponzao的回答是正确的。但请注意,Cursive实际上可以为你填写存根:你可以写(reify Action)然后(用光标在某处),选择 Code-> Generate ... 并选择实施方法。然后草书将以正确的形式填充存根。这当前仅适用于实现接口而非协议。