Создание библиотеки протоколов и defrecords для использования из Java

На данный момент у меня есть полностью функциональная библиотека Clojure, которая вызывается из Java.

То, как я это делаю: у меня есть файл, который использует gen-class для обертывания всего API как статических методов одного класса и передает данные внутрь и наружу в форме IPersistentVector и IPersistentMap.

Однако сейчас я занимаюсь рефакторингом библиотеки и добавляю функциональность в различные протоколы.

У меня есть четыре протокола, назовем их A, B, C и D. И две defrecords, X и Y. X и Y реализуют протоколы A, B и C. В то время как Y также реализует D.

Что мне нужно сделать, чтобы сделать их доступными для Java? Доступны ли они автоматически как интерфейсы и классы? Или мне еще нужно сделать аналог gen-class, чтобы сделать их общедоступными?

Если нет, то что является эквивалентом предложения gen-class: methods, в котором я определяю типы Java для аргументов методов?

Есть ли у кого-нибудь простой пример предоставления доступа к протоколам и записям для Java?


person interstar    schedule 30.08.2015    source источник


Ответы (1)


defprotocol

Каждый протокол Clojure также является интерфейсом Java с тем же именем и методами. Если я возьму пример из ibm developerworks, мы увидим, что:

(ns com.amalgamated)

(defprotocol Fulfillment
  (invoice [this] "Returns an invoice")
  (manifest [this] "Returns a shipping manifest"))

Эквивалентно :

package com.amalgamated;

public interface Fulfillment {
    public Object invoice();
    public Object manifest();
}

На Clojure.org также есть некоторая (довольно краткая) информация по этому поводу.

Клиент Java, желающий участвовать в протоколе, может сделать это наиболее эффективно, реализовав интерфейс, созданный протоколом. Внешние реализации протокола (которые необходимы, когда вы хотите, чтобы класс или тип, не входящие в ваш контроль, участвовали в протоколе), могут быть предоставлены с помощью конструкции расширения:

(extend AType   AProtocol   
 {:foo an-existing-fn
    :bar (fn [a b] ...)
    :baz (fn ([a]...) ([a b] ...)...)}   BProtocol
    {...} ...)

definterface

Если вы стремитесь к производительности, вы можете рассмотреть возможность использования definterface, который используется аналогично протоколам. В этом сообщении SO также есть подробности о том, как его использовать:

(definterface Foo
  [^int foo [x ^String y]]
  [^void bar [^ints is]])

definterface кажутся быстрее, чем протоколы.

defrecord

Точно так же records (а также deftype и definterface) будут генерировать классы Java. Опять же, Clojure.org/datatypes содержит полезную информацию (выделено мной):

deftype и defrecord динамически генерируют скомпилированный байт-код для именованного класса с набором заданных полей и, необязательно, методов для одного или нескольких протоколов и / или интерфейсов < / сильный>. Они подходят для динамической и интерактивной разработки, не требуют компиляции AOT и могут быть повторно оценены в течение одного сеанса. Они похожи на defstruct при создании структур данных с именованными полями, но отличаются от defstruct тем, что: [...]

Так что да, если он будет доступен с Java. Только будьте осторожны с именами.

В качестве побочного примечания вы можете взглянуть на вызов Clojure из Java.

person nha    schedule 04.09.2015