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

如何使用与clojure.core函数同名的协议扩展java类?,clojure,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 co

我试图用以下协议扩展一个简单的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”,则必须在名称空间声明中排除clojure.core版本

(ns so.protocols 
  (:refer-clojure :exclude [count]))
现在,在该名称空间中,您可以使用“count”方法定义协议。如果您想在该名称空间中使用count的核心版本,可以在名称空间中为其添加前缀
clojure.core/count

然后,协议的用户将希望别名您的命名空间。比如说,

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

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

有函数
clojure.core/count
和协议中定义的方法
count
。正如警告所说:通过创建一个名为
count
的方法的接口,您可以将名为
count
的别名覆盖到
clojure.core/count

(范围5)
返回的
LazySeq
对象未实现您的
countable
协议。您仍然可以使用
(clojure.core/count(range 5))
进行计数


您可能想做的是实现接口而不是自己的接口。

多亏了大家

我在这里发布了我为这个案例找到的2个工作解决方案,感谢大家的评论

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

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

(defmulti count type)

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



这对我来说是可行的,尽管我想做的是(在使用ns colission时,我意识到我的概念错误)在同一个ns中使用不同接口的“同名方法”:。。。假设我受到clojure/java interop sintaxis的影响(该参数定义了fn,而不是相反)–

协议方法导致在当前名称空间中定义相同名称的函数。当您从某些Clojure代码调用协议方法时,您实际调用的是一个生成的函数,该函数将查找并分派到相应的实现。提前感谢Alex,但是您将如何解决这种情况“当前命名空间冲突”?与任何其他命名空间冲突相同,如下面的答案所述。事实上,它恰好是导致冲突的协议方法并不重要。感谢@Alex,我在下面发布了本案例的两个工作解决方案,使用multimethods和extending protocol,都更改了函数名“您可能想做的是实现clojure.lang.Counted接口,而不是您自己的接口。”-不幸的是,OP希望将协议扩展到现有的Java类-没有迹象表明可以修改该类。然后他应该通过defrecord或使用reify.sorry@lgrapenthin创建Clojure包装。我已取消选中您的解决方案,因为我无法修改Java类,并且,defrecord或reify也不起作用,因为有时我不创建实例:(您有两个选项:1.您创建ToxicLib的全功能Clojure包装器(至少是您直接或间接使用的功能)。这是一个很大的工作,只有在有显著好处的情况下才应该做。2.我的建议是:直接使用Java Interop,这是Clojure中的一个常见习惯用法-
ColorList
甚至不是不变的,所以为什么要使它适合Clojure?只需使用
。size
-其他一切都会让代码的读者感到困惑(我认为-这是Clojure coll?)。感谢您解释解决此名称空间重叠的详细信息!但我的问题(没有很好地解释)也与表达式问题有关,然后我想在相同的情况下使用同名方法interfaz。
(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