如何确定该类型实现的协议?

时间:2016-03-13 11:47:48

标签: reflection clojure clojurescript

鉴于某种类型或记录,我如何获得它实现的所有协议?

我们说我们有以下代码:

(defprotocol P1
  (op1 [this]))

(defprotocol P2
  (op2 [this]))

(defrecord R []
  P1
  (op1 [_] 1)
  P2
  (op2 [_] 2))

我需要的是一个像这样的函数:

(all-protocols-for-type R) ;; => (P1 P2)

如果有后端攻击的话会很好,因为我希望有一个Clojure和ClojureScript的机制。

UPD:这样做的目的是内省特定类型提供的功能。让我们这样说:

user> (supers (type {}))
#{clojure.lang.AFn clojure.lang.ILookup java.lang.Object java.util.Map clojure.lang.Seqable java.lang.Runnable clojure.lang.IPersistentCollection java.io.Serializable clojure.lang.IFn clojure.lang.APersistentMap clojure.lang.Associative java.util.concurrent.Callable clojure.lang.IKVReduce clojure.lang.Counted clojure.lang.IMeta clojure.lang.IMapIterable java.lang.Iterable clojure.lang.IPersistentMap clojure.lang.IEditableCollection clojure.lang.IObj clojure.lang.MapEquivalence clojure.lang.IHashEq}

我知道我可以将map用作函数(IFn),在那里按键查找值(Associative),甚至可以在其上reduce-kv IKVReduce })。

3 个答案:

答案 0 :(得分:3)

这是你在Clojure中最接近而不做一些疯狂的事情:

(require '[clojure.set :as set])

(deftype EmptyType [])

(defrecord EmptyRecord [])

(defn all-protocols-for-type [t]
  (map (comp symbol (memfn getSimpleName))
       (set/difference (supers t)
                       (set/union (supers EmptyType)
                                  (supers EmptyRecord)))))

我使用了特定的map来获得与您在问题中提供的格式相同的输出;你应该根据需要修改映射函数。

基本上,你要问的是this硬币的另一面。使用deftypedefrecord扩展协议存储有关类型的信息,并使用extend-typeextend-protocol存储有关协议信息的扩展名。

因此,如果您的所有扩展程序都是直接在deftypedefrecord中完成的,那么您可以使用我上面给出的方法获取给定类型的所有协议。如果您的所有扩展程序都使用extend-typeextend-protocol完成,则可以使用Alex在回答其他问题时提供的方法获取给定协议的所有类型。但是,在所有情况下都不是一个很好的方法。

答案 1 :(得分:1)

至少在JVM上这是不可能的,因为将类型扩展到协议只会在协议上留下关于类型的信息。在clojurescript中,我不确定。你为什么要这个?如果您甚至不知道这些协议的用途,那么拥有协议列表并不是非常有用。

答案 2 :(得分:0)

  

我需要的是一个像这样的函数:

(all-protocols-for-type R) ;; => (P1 P2)

我不可能想到为类型实现的协议列表的任何实际效用,除非此列表将与另一个协议引用列表进行比较。

如果已知协议引用(在第二个列表中),则会执行以下操作:

(defn extends-all? [protocols typ]
  (reduce (fn [acc p] (and acc (extends? p typ)))
          true
          protocols))
(extends-all? [P1 P2] R) ;; => true

如果目标不是与协议列表进行比较,请使用实际用例更新问题。