Clojure:列出在命名空间内实现某些协议的所有deftypes

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

我已经找到了从(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中实现任何Java接口或defrecord,而不仅仅是一个协议).找到以这种方式扩展协议的类型的任何方法都需要进行一些扫描和反射.基本上你要问的是,“我怎样才能找到实现给定接口的所有Java类?”

在典型的Java应用程序中,您可能会按照扫描.class文件的类路径目录和对它们进行内省检查的方式执行某些操作,但这在Clojure中不起作用,因为很可能不是类型的.class文件(字节码是动态生成的).如果您对自己的实现不满意,可以查看这个问题的答案,看看它是否更符合您的喜好:

Find Java classes implementing an interface

相关文章
相关标签/搜索