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

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

Я пробовал использовать reify, proxy и 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)


person byrongibby    schedule 20.12.2018    source источник


Ответы (1)


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

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

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

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

Без тестирования я полагаю, что решение будет использовать функцию 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)))))])
person Shlomi    schedule 20.12.2018
comment
Привет @Шломи. Первое предложение возвращает: IllegalArgumentException Не знаю, как создать ISeq из: app.core$eval92$reify__93 clojure.lang.RT.seqFrom (RT.java:487) Второе предложение работает отлично! Большое спасибо за вашу помощь, я сидел на этом в течение нескольких дней. - person byrongibby; 21.12.2018
comment
Ой! Конечно, я немного ошибся. into-array требует последовательности. Спасибо, что указали мне на это, пожалуйста, посмотрите обновленный ответ. Рад, что это помогло вам! - person Shlomi; 21.12.2018