如何从 Clojure 中的 class 调用具体化的 Java 接口?来电无法解决

How to call a reified Java interface from a class in Clojure? Call can't be resolved

我正在尝试将一些 Java 代码直接翻译成 raspberry pi 上的 Clojure。我坚持在方法调用中实现接口 - addListener。

我尝试过使用 reify、proxy 和 deftype。通过 reify,我尝试向编译器提供尽可能多的提示。

这是原文Java code:

myButton.addListener(new GpioPinListenerDigital() {
  @Override
  public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
  System.out.println(" --> GPIO PIN STATE CHANGE: " + event.getPin() + " = " + event.getState());
 }
});

这是我翻译的 Clojure 代码:

(.addListener myButton
              (reify GpioPinListenerDigital
                (^void handleGpioPinDigitalStateChangeEvent [this ^GpioPinDigitalStateChangeEvent event]
                 (println (str " --> GPIO PIN STATE CHANGE: " (.getPin event) " = " (.getState event))))))

我总是以同样的错误结束:

IllegalArgumentException No matching method found: addListener for class com.pi4j.io.gpio.impl.GpioPinImpl clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:79)

我不熟悉为 raspberry pi 编写 Java,但是查看 javadoc 我们看到以下声明:

public void addListener(GpioPinListener... listener);
public void addListener(List<? extends GpioPinListener> listeners);

两者都接受了大量的听众,而不仅仅是一个。在上面提供的 Java 示例中,java 编译器透明地将单个侦听器实例转换为单向量,并使用上面显示的第一个定义。

clojure 编译器不知道该怎么做,你必须帮助它。这个问题基本上可以归结为 how to call variadic java functions from clojure.

如果不对此进行测试,我相信解决方案将使用 clojure 的 into-array 函数,因此类似于以下内容:

(.addListener myButton
              (into-array GpioPinListenerDigital
                [(reify GpioPinListenerDigital
                  (^void handleGpioPinDigitalStateChangeEvent [this ^GpioPinDigitalStateChangeEvent event]
                   (println (str " --> GPIO PIN STATE CHANGE: " (.getPin event) " = " (.getState event)))))]))

您可能需要稍微扭曲一下,但我相信这是您面临的核心问题。

编辑

由于上面的第二个声明,另一种可能的解决方案可能只是将其包装在一些常规列表中,例如向量:

(.addListener myButton
              [(reify GpioPinListenerDigital
                (^void handleGpioPinDigitalStateChangeEvent [this ^GpioPinDigitalStateChangeEvent event]
                 (println (str " --> GPIO PIN STATE CHANGE: " (.getPin event) " = " (.getState event)))))])