3

clojure.java.jmx在一个Destract使用objects->data.

当我完成单个数据结构时,应该可以做一个(walk/prewalk jmx/objects->data (jmx/operations "java.lang:type=Threading")).

然而,在Destract协议中有一个函数的实现,这意味着地图将被错误地处理。我可以在我的命名空间中添加一个实现,但因为它也是地图的接口,所以这不起作用。objects->dataclojure.lang.Associativeclojure.lang.IPersistentMapclojure.lang.Associative

因为它,我最终不得不分叉clojure.java.jmx。如果有办法改变偏好,或者收回另一个命名空间中的类型的协议,我就不必这样做了。

有没有办法防止在协议中clojure.lang.Associative优先 clojure.lang.IPersistentMap

如果没有,是否可以为另一个命名空间中的类型撤回协议?关于将协议编译成 Java 接口的方式,甚至有可能实现它吗?

4

1 回答 1

1

它应该工作

你确定提供你自己的实现是clojure.lang.IPersistentMap行不通的吗?它适用于我的 REPL 会话。当我只是覆盖默认实现时,它甚至可以工作clojure.lang.Associative

user=> (ns ns1)
;;=> nil

ns1=> (defprotocol IPrintable (prnt [this]))
;;=> IPrintable

ns1=> (extend-protocol IPrintable clojure.lang.Associative (prnt [this] (str "clojure.lang.Associative " this)))
;;=> nil

ns1=> (ns ns2)
;;=> nil

ns2=> (ns1/prnt {:a 1})
;;=> "clojure.lang.Associative {:a 1}"

ns2=> (extend-protocol ns1/IPrintable clojure.lang.Associative (prnt [this] (str "My custom impl for clojure.lang.Associative " this)))
;;=> nil

ns2=> (ns1/prnt {:a 1})
;;=> "My custom impl for clojure.lang.Associative {:a 1}"

它也适用于示例项目

如果它没有被另一个命名空间传递加载,你必须记住require你所在的命名空间。extend-protocol重要的是,您extend-protocol将在您想要覆盖的那个之后加载。

在内部extend-protocolextend-type修改附加到协议元数据的特殊映射,其中它assoc是具有函数实现的给定类型。如果给定类型存在现有条目,它将被覆盖。因此,执行的顺序extend-*很重要。

当它不起作用时

当对象直接实现接口或协议时(例如 inline in defrecord),您不能覆盖实现(继续 REPL 会话):

ns2=> (defrecord SomeData []
        ns1/IPrintable (prnt [this] "I'm SomeData"))
;;=> ns2.SomeData

ns2=> (ns1/prnt (SomeData.))
;;=> "I'm SomeData"

ns2=> (extend-protocol ns1/IPrintable SomeData (prnt [this] "Custom impl " this))
;;=> IllegalArgumentException class ns2.SomeData already directly implements interface ns1.IPrintable for protocol:#'ns1/IPrintable  clojure.core/extend (core_deftype.clj:775)
于 2016-03-30T17:12:30.140 回答