如何使用与clojure.core函数同名的方法扩展java类?

时间:2014-04-23 18:44:31

标签: clojure

我试图用这个协议扩展一个简单的java类toxi.color.ColorList

(defprotocol countable
  (count [this]))

(extend-protocol countable
  ColorList
  (count [this]
    (.size this)))

当我评估此代码时,我会看到这些警告

Warning: protocol #'dat00.protocols/countable is overwriting function count

WARNING: count already refers to: #'clojure.core/count in namespace: dat00.protocols, being replaced by: #'dat00.protocols/count

但这很好用:

(count (ColorList.))
=> 0

但是如果我在同一个文件(或命名空间)中尝试这个

(count (range 5))
=> IllegalArgumentException No implementation of method: :count of protocol: #'dat00.protocols/countable found for class: clojure.lang.LazySeq  clojure.core/-cache-protocol-fn (core_deftype.clj:541)

所以我的问题是:
我是否误解了有关协议的一些细节?

谢谢!

3 个答案:

答案 0 :(得分:4)

您有命名空间冲突。

定义协议时,您将在当前命名空间中定义调度函数。如果确实想要使用“count”,则必须在命名空间声明中排除clojure.core版本。

(ns so.protocols 
  (:refer-clojure :exclude [count]))

现在,在该命名空间中,您可以使用“count”方法定义协议。如果您希望在该命名空间中使用核心版本的count,则可以将其命名为clojure.core/count

您的协议的用户将希望为您的命名空间添加别名。例如,

(ns user 
  (:require [so.protocols :as p]))

因此p/count是您的协议方法,count是核心。

答案 1 :(得分:4)

您的协议clojure.core/count中定义了函数count和方法countable。如警告所示:通过创建具有名为count的方法的接口,将名为clojure.core/count的别名覆盖为count

LazySeq返回的(range 5)对象未实现您的countable协议。你仍然可以用(clojure.core/count (range 5))计算它。

您可能要做的是实现clojure.lang.Counted界面而不是您自己的界面。

答案 2 :(得分:0)

感谢所有人,

我在这里发布了2个工作解决方案我已经达成了这个案例,感谢所有的评论

在所有情况下,我都必须更改功能的名称

似乎多方法(我还不确定性能后果......)可以解决这里的表达问题

(defmulti count type)

(defmethod count toxi.color.ColorList [a]
  (.size a))
(defmethod  count clojure.lang.LazySeq [a]
  (count a))

(defprotocol countable
  (get-count [this]))

(extend-protocol countable
  ColorList
  (get-count [this]
    (.size this))
  clojure.lang.LazySeq
    (get-count [this]
    (.count this))
  )

(get-count (ColorList.)) => 0
(get-count (range 5)) => 5

对我来说很有用,虽然我想做的事情(以及我意识到我的概念错误的ns colission)是在同一个ns中使用不同接口的“同名方法”:) ...假设我受到clojure / java interop sintaxis的影响(参数定义了fn而不是相反) -