Как найти реализованные протоколы в объекте Clojure? - PullRequest
10 голосов
/ 11 января 2011

Есть ли документированный способ узнать, какие протоколы реализованы объектом Clojure? Обратный путь (показать, для каких классов данный протокол расширен) прост: (протокол расширений).

Ответы [ 3 ]

6 голосов
/ 13 января 2011

В итоге я получил следующую реализацию:

(defn protocol? [maybe-p]
  (boolean (:on-interface maybe-p)))

(defn all-protocols []
  (filter #(protocol? @(val %)) (ns-publics *ns*)))

(defn implemented-protocols [sym]
  (filter #(satisfies? @(val %) sym) (all-protocols)))

Сначала он ищет все символы в текущем пространстве имен (вы, конечно, можете распространить это на все пространства имен), независимо от того, являются ли они определениями протокола или net (все-протоколы).Затем он ищет данный символ, если он удовлетворяет одному из этих протоколов.

Протокол?Функция использует ключ: на интерфейсе, который не задокументирован, поэтому эта функция не переносима.

0 голосов
/ 11 декабря 2018

Старый вопрос, и есть принятый ответ ... однако я, возможно, сделал бы что-то вроде этого:

(defprotocol FooP
  (foo [this]))

(defrecord Foo []
  FooP
  (foo [this] :whatever))

если вы знаете протокол, который вы хотите проверить, тогда вы можете использовать satisfies?

> (satisfies? FooP (->Foo))
true

Если нет, то вы могли бы по крайней мере найти все интерфейсы, используя следующее

(defn interfaces [o]
  (for [interface (.getInterfaces (class o))]
    (.getCanonicalName ^Class interface)))

который вы можете проверить

> (interfaces (->Foo))
("com.beoliver.FooP" "clojure.lang.IRecord" "clojure.lang.IHashEq" "clojure.lang.IObj" "clojure.lang.ILookup" "clojure.lang.IKeywordLookup" "clojure.lang.IPersistentMap" "java.util.Map" "java.io.Serializable")

> (interfaces [])
("clojure.lang.IObj" "clojure.lang.IEditableCollection" "clojure.lang.IReduce" "clojure.lang.IKVReduce")

> (interfaces {})
("clojure.lang.IObj" "clojure.lang.IEditableCollection" "clojure.lang.IMapIterable" "clojure.lang.IKVReduce")

Если вы отобразите bean через интерфейсы, не вызывая .getCanonicalName, вы сможете увидеть все опции.

0 голосов
/ 11 января 2011

Сейчас я не могу попробовать это, но вы можете попробовать метод класса Java: getGenericInterfaces. Это должно дать вам список интерфейсов. Возможно, есть и другие способы получения этой информации с использованием аналогичных методов, но я не смотрел.

Если вы также посмотрите на исходный код, вы увидите, как настраиваются протоколы (вы можете получить доступ к источнику, нажав на ссылки в API clojure). В Clojure 1.3 есть «приватная» функция, которая выглядит следующим образом:

(defn- protocol?
  [maybe-p]
  (boolean (:on-interface maybe-p)))

Эта функция используется функцией extend Clojure, чтобы проверить, действительно ли вы предоставили протокол. Если вы сделаете свою собственную функцию подобной, вы можете отфильтровать результаты getGenericInterfaces. Поскольку это внутренняя деталь, она может быть изменена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...