Как вызвать интерфейс 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)))))])