Clojure:列出在命名空间内实现某些协议的所有 deftype [英] Clojure: Listing all deftypes that implement some protocol within the namespace

查看:22
本文介绍了Clojure:列出在命名空间内实现某些协议的所有 deftype的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个协议和几个在一个工作区中实现它的定义类型.如何列出实现以下协议的所有定义类型?

I have a protocol and several deftypes implementing it within one workspace. How can I list all deftypes that implement following protocol?

我已经找到了从 (ns-public) 过滤数据的解决方案,但我不喜欢它,因为它使用了一些魔法"来完成工作,因为我还没有找到正确的方法来通过satisfies?extends? 实现我的目标.

I've came to the solution that filters data from (ns-public), but I don't like it, because it uses some "magic" to get the work done, as I haven't found proper way to achieve my goal with satisfies? and extends?.

有什么想法吗?

(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-typeextend-protocol 函数将任何现有的 Java 类扩展为协议(这是一个非常强大的功能,因为它允许您将代码扩展到使用内置 Java 或 Clojure 类型,或您无法控制的其他第三方类型).或者,您可以将协议实现直接指定为 deftypedefrecord 中类型定义的一部分.这两种机制的实现方式不同.

In general, this is going to be a hairy problem to solve because there are two different ways a type can satisfy a protocol. You can extend any existing Java class to a protocol using the extend-type and extend-protocol functions (this is a very powerful feature because it allows you to extend your code to work with built-in Java or Clojure types, or other third-party types that you don't control). Or, you can specify a protocol implementation directly as part of a type definition in deftype or defrecord. These two mechanisms are implemented differently.

第一种情况(通过 extend-typeextend-protocol 扩展)对你来说更容易解决,因为要扩展的类型将被附加到协议本身(协议本质上相当于一个生成的 Java 接口加上一个带有关于协议元数据的 Clojure 映射).您可以通过查看协议映射中的 :impls 键来找到扩展协议的类型:

The first case (extension via extend-type or extend-protocol) is going to be easier for you to solve because the type being extended is going to be attached to the protocol itself (a protocol essentially amounts to a generated Java interface plus a Clojure map with metadata about the protocol). You can find the types that extend the protocol by looking at the :impls key in the protocol map:

user=> (defprotocol MyProtocol (foo [this] "Protocol function"))
user=> (deftype MyType [])
user=> (extend-type MyType MyProtocol (foo [_] "hello foo!"))
user=> (keys (:impls MyProtocol))
(user.MyType)

第二种情况(通过 deftypedefrecord 直接实现协议)更困难,因为正在发生的事情是为类型或记录生成的 Java 类将直接实现协议定义的 Java 接口(您可以在 deftypedefrecord 中实现任何 Java 接口,而不仅仅是协议).任何找到以这种方式扩展协议的类型的方法都需要进行一些扫描和反射.本质上,您要问的是,我怎样才能找到实现给定接口的所有 Java 类?"

The second case (directly implementing a protocol via deftype or defrecord) is more difficult because what's happening is the Java class generated for the type or record will directly implement the Java interface defined by the protocol (you can implement any Java interface in a deftype or defrecord, not just a protocol). Any approach to find types that extend a protocol in this manner is going to require some deal of scanning and reflection. Essentially what you're asking is, "how can I find all the Java classes implementing a given interface?"

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

In a typical Java application, you might do something along the lines of scanning the directories of the classpath for .class files and introspecting on them, but this won't work in Clojure because there very well might not be .class files for your types (the bytecode is generated dynamically). If you're not satisfied with your own implementation, you might check out the answer in this question and see if it's more to your liking:

查找实现接口的 Java 类

这篇关于Clojure:列出在命名空间内实现某些协议的所有 deftype的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆