Как вызвать интерфейс Java из класса в Clojure? Звонок не может быть решен

Я пытаюсь перевести некоторый код Java прямо в Clojure на Raspberry Pi. Я застрял при реализации интерфейса в вызове метода - addListener.

Я пытался использовать reify, прокси и deftype. С помощью reify я попытался предоставить как можно больше подсказок компилятору.

Это оригинальный код Java:

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 Не найдено подходящего метода: addListener для класса com.pi4j.io.gpio.impl.GpioPinImpl clojure.lang.Reflector.invokeMatchingMethod (Reflector.java:79)

1 ответ

Решение

Я не знаком с написанием Java для Raspberry Pi, но, глядя на Javadoc, мы видим следующие объявления:

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

Оба принимают множество слушателей, а не только один. В приведенном выше примере с Java Java-компилятор прозрачно превращает отдельный экземпляр прослушивателя в вектор сингелтона и использует первое определение, показанное выше.

Компилятор clojure не знает, как это сделать, вы должны помочь ему. По сути, вопрос сводится к тому, как вызывать Java-функции с переменным значением из clojure.

Без проверки этого, я считаю, что решение будет использовать Clojure's 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)))))])
Другие вопросы по тегам