【问题标题】:Clojure: Listing all deftypes that implement some protocol within the namespaceClojure:列出在命名空间内实现某些协议的所有定义类型
【发布时间】:2013-01-09 21:35:39
【问题描述】:

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

我已经找到从 (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"
)

【问题讨论】:

    标签: clojure protocols


    【解决方案1】:

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

    第一种情况(通过extend-typeextend-protocol 扩展)将更容易解决,因为被扩展的类型将附加到协议本身(协议本质上相当于生成的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)
    

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

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

    Find Java classes implementing an interface

    【讨论】:

    • 谢谢,那我会明确地使用extend-type。
    • 我已经尝试过您的解决方案,但我找不到创建 deftype 实例的方法 - (find-protocol-impl MyProtocol (first (keys (:impls MyProtocol)))) 没有似乎工作。我也尝试了以下方法(osdir.com/ml/clojure/2010-03/msg01314.html)——仍然没有结果:(
    • 玩过 macoexpand 后发现 ((resolve (symbol "->MyType"))) 有效。终于
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-04
    • 2014-12-22
    相关资源
    最近更新 更多