Reflection 如何确定该类型实现了哪些协议?

Reflection 如何确定该类型实现了哪些协议?,reflection,clojure,clojurescript,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) (all-protocols-for-type R) ;; =>

给定某种类型或记录,如何获取它实现的所有协议

假设我们有以下代码:

(defprotocol P1
  (op1 [this]))

(defprotocol P2
  (op2 [this]))

(defrecord R []
  P1
  (op1 [_] 1)
  P2
  (op2 [_] 2))
我需要的是这样一个函数:

(all-protocols-for-type R) ;; => (P1 P2)
(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,在那里按键查找值,甚至在它上面减少kv IKVReduce。

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

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

这是在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)))))
我使用那个特定的映射只是为了得到一个与你在问题中给出的格式相同的输出;您应该根据需要修改映射函数

基本上,你所要求的是硬币的另一面。使用deftype或defrecord对协议进行扩展时会存储该类型的信息,而使用extend type或extend protocol进行扩展时会存储该协议的信息


因此,如果您的所有扩展都直接在deftype或defrecord中完成,那么您可以使用上面给出的方法获得给定类型的所有协议。如果您的所有扩展都是使用扩展类型或扩展协议完成的,那么您可以使用Alex在回答另一个问题时给出的方法获得给定协议的所有类型。但在所有情况下,都没有一个好方法可以同时做到这两个方面。

这是在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)))))
我使用那个特定的映射只是为了得到一个与你在问题中给出的格式相同的输出;您应该根据需要修改映射函数

基本上,你所要求的是硬币的另一面。使用deftype或defrecord对协议进行扩展时会存储该类型的信息,而使用extend type或extend protocol进行扩展时会存储该协议的信息

因此,如果您的所有扩展都直接在deftype或defrecord中完成,那么您可以使用上面给出的方法获得给定类型的所有协议。如果您的所有扩展都是使用扩展类型或扩展协议完成的,那么您可以使用Alex在回答另一个问题时给出的方法获得给定协议的所有类型。但在所有情况下,并没有一个好方法可以同时做到这两个方面

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

(all-protocols-for-type R) ;; => (P1 P2)
(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
如果目标不是与协议列表进行比较,请使用实际用例更新问题

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

(all-protocols-for-type R) ;; => (P1 P2)
(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

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

supers也会返回接口,值得一提的是,因为问题仅用于查询协议。否则我喜欢这个答案。好奇的如何区分接口和协议?@muhuk很好!当我写函数时,我正在考虑这个问题,但是当我写答案时,我已经忘记了。正如Alex在中指出的,接口和协议之间的区别在于,协议除了接口本身之外还存储额外数据的映射。我想您可以使用差分返回的类,对它们进行一些名称更改,并使用它们来查找协议,但我不确定是否有更好的选择。太好了!事实上,我完全同意只使用超级。我不知道它存在。supers也会返回接口,值得一提的是,因为问题只针对查询协议。否则我喜欢这个答案。好奇的如何区分接口和协议?@muhuk很好!当我写函数的时候,我正在考虑这个问题,但是当我写函数的时候,我已经忘记了
答复正如Alex在中指出的,接口和协议之间的区别在于,协议除了接口本身之外还存储额外数据的映射。我想您可以使用差分返回的类,对它们进行一些名称更改,并使用它们来查找协议,但我不确定是否有更好的选择。太好了!事实上,我完全同意只使用超级。不知道它存在。您也可以使用hara.class.heritation/祖先树RYou也可以使用hara.class.heritation/祖先树R