给定某种类型或记录,我如何获取它实现的所有协议(protocol)?
假设我们有以下代码:
(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:这样做的目的是内省(introspection)特定类型提供的功能。让我们说,通过这样做:
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
)。
最佳答案
这是在 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 。使用 deftype
或 defrecord
的协议(protocol)扩展存储有关类型的信息,并使用 extend-type
或 extend-protocol
存储协议(protocol)信息。
因此,如果您的所有扩展都直接在 deftype
或 defrecord
中完成,您可以使用我上面给出的方法获取给定类型的所有协议(protocol)。如果您的所有扩展都是使用 extend-type
或 extend-protocol
完成的,您可以使用 Alex 在其他问题的回答中给出的方法获取给定协议(protocol)的所有类型问题。但并没有一个好的方法可以在所有情况下都做到这两点。
关于reflection - 如何确定该类型实现了哪些协议(protocol)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35969848/