Clojure:列出在名称空间中实现某些协议的所有DefType

Clojure:列出在名称空间中实现某些协议的所有DefType,clojure,protocols,Clojure,Protocols,我有一个协议和几个deftypes在一个工作区内实现它。如何列出实现以下协议的所有DefType 我找到了从(ns public)过滤数据的解决方案,但我不喜欢它,因为它使用了一些“魔法”来完成工作,因为我还没有找到合适的方法来实现我的目标?并且延伸 有什么想法吗 (defprotocol Protocol (foo[this] "just an interface method")) (deftype Dummy [] Protocol (foo[this] "bar")) (

我有一个协议和几个deftypes在一个工作区内实现它。如何列出实现以下协议的所有DefType

我找到了从(ns public)过滤数据的解决方案,但我不喜欢它,因为它使用了一些“魔法”来完成工作,因为我还没有找到合适的方法来实现我的目标?并且延伸

有什么想法吗

(defprotocol Protocol
  (foo[this] "just an interface method"))


(deftype Dummy [] Protocol
  (foo[this] "bar"))


(defn implements? [protocol atype] "fn from clojure sources"
  (and atype (.isAssignableFrom ^Class (:on-interface protocol) atype)))


(defn list-types-implementing[protocol]
  (filter (fn[x] (let [[a b] x]
            (when (.startsWith (str a) "->") ; dark magic        
              (implements? protocol 
               (resolve (symbol 
                (.replace (str a) "->" "")))))
            )) 
         (ns-publics *ns*)))

(list-types-implementing Protocol) ; => ([->Dummy #'user/->Dummy])

(let [[a b] (first(list-types-implementing Protocol))]
    (foo (b)) ; => "bar"
)

一般来说,这将是一个需要解决的棘手问题,因为一个类型可以通过两种不同的方式满足协议。您可以使用
extend type
extend protocol
函数将任何现有Java类扩展到协议(这是一个非常强大的功能,因为它允许您将代码扩展到内置Java或Clojure类型,或其他您无法控制的第三方类型)。或者,您可以在
deftype
defrecord
中直接将协议实现指定为类型定义的一部分。这两种机制的实现方式不同

第一种情况(通过
扩展类型
扩展协议
进行扩展)将更容易解决,因为要扩展的类型将附加到协议本身(协议实质上相当于生成的Java接口加上包含协议元数据的Clojure映射)。通过查看协议映射中的
:impls
键,可以找到扩展协议的类型:

user=> (defprotocol MyProtocol (foo [this] "Protocol function"))
user=> (deftype MyType [])
user=> (extend-type MyType MyProtocol (foo [_] "hello foo!"))
user=> (keys (:impls MyProtocol))
(user.MyType)
第二种情况(通过
deftype
defrecord
直接实现协议)更为困难,因为为类型或记录生成的Java类将直接实现协议定义的Java接口(您可以在
deftype
defrecord
中实现任何Java接口,而不仅仅是协议)。任何以这种方式查找扩展协议的类型的方法都需要一些扫描和反射。本质上,您要问的是,“如何找到实现给定接口的所有Java类?”

在一个典型的Java应用程序中,您可能会在类路径的目录中扫描.class文件并对其进行内省,但这在Clojure中不起作用,因为您的类型可能没有.class文件(字节码是动态生成的)。如果您对自己的实现不满意,可以查看此问题的答案,看看是否更符合您的喜好:


谢谢,然后我将显式使用extend type。我已经尝试了您的解决方案,但是我找不到创建deftype实例的方法-(find protocol impl MyProtocol(first(key(:impls MyProtocol)))似乎不起作用。此外,我还尝试了以下()方法-仍然没有结果:(在玩macoexpand之后,发现((resolve(symbol)))“->MyType”))有效。终于