鉴于某种类型或记录,我如何获得它实现的所有协议?
我们说我们有以下代码:
(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
})。
答案 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硬币的另一面。使用deftype
或defrecord
扩展协议存储有关类型的信息,并使用extend-type
或extend-protocol
存储有关协议信息的扩展名。
因此,如果您的所有扩展程序都是直接在deftype
或defrecord
中完成的,那么您可以使用我上面给出的方法获取给定类型的所有协议。如果您的所有扩展程序都使用extend-type
或extend-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
如果目标不是与协议列表进行比较,请使用实际用例更新问题。