在 Clojure 中扩展 Java 接口时出错
Posted
技术标签:
【中文标题】在 Clojure 中扩展 Java 接口时出错【英文标题】:Errors extending a Java Interface in Clojure 【发布时间】:2016-04-26 10:40:50 【问题描述】:我有一个基本的 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 (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 答案似乎表明这是论点数量的问题,但我不知道如何解决它。我做错了什么??
【问题讨论】:
【参考方案1】:您缺少函数中的 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 了解更多信息。
【讨论】:
啊,成功了,谢谢!包括this
引用消除了编译器错误,REPL 中的以下代码按预期工作:(.execute (action (fn [metadata parameter] (println "Test action"))) nil nil)
@OliverMooney,很高兴为您提供帮助!【参考方案2】:
ponzao 的回答是正确的。但请注意,Cursive 实际上可以为您填写存根:您可以编写 (reify Action)
然后(在该表单中的某处使用光标)选择 Code->Generate... 并选择实现方法.然后草书将用正确的形式填写存根。这目前仅在实现接口而非协议时有效。
【讨论】:
我没有意识到,谢谢!我主要使用 IntelliJ 作为 Cursive 的主机,到目前为止,大多数面向 Java 的菜单选项都是未知数...以上是关于在 Clojure 中扩展 Java 接口时出错的主要内容,如果未能解决你的问题,请参考以下文章
Java扩展Nginx之二:编译nginx-clojure源码
精选版:用Java扩展Nginx(nginx-clojure 入门)