它应该工作
你确定提供你自己的实现是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-protocol
或extend-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)