2014-04-23 58 views
2

我試圖延長一個簡單的Java類toxi.color.ColorList這個協議:如何擴展具有與clojure.core函數名稱相同的方法的協議的java類?

(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) 

所以我的問題是:
我誤解了有關協議的一些細節?

謝謝!

+1

協議方法導致在當前名稱空間中定義具有相同名稱的函數。當你從一些Clojure代碼中調用一個協議方法時,你實際調用的是一個生成的函數,它查找併發送到適當的實現。 – Alex

+0

在此先感謝亞歷克斯,但你會如何解決這種情況「當前名稱空間衝突」? – tangrammer

+1

與其他命名空間衝突一樣,如下面的答案中所述。它碰巧是導致衝突的協議方法的事實並不重要。 – Alex

回答

4

您有名稱空間衝突。

定義協議時,您正在當前名稱空間中定義調度函數。如果你確實想要使用「count」,你必須在你的命名空間聲明中排除clojure.core版本。

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

現在在該命名空間中,您可以使用「count」方法定義協議。如果您希望在該名稱空間中使用核心版本的計數,則可以使用名稱空間作爲它的前綴clojure.core/count

你的協議的用戶會想要別名你的名字空間。例如,

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

這樣p/count是你的協議方法和count是核心。

+0

感謝解釋細節,以解決這個命名空間重疊!但我的問題(不能很好地解釋)也涉及到表達問題http://stackoverflow.com/questions/3596366/what-is-the-expression-problem的話,我想用同樣的名稱的方法,interfaz在相同的情況下。 – tangrammer

4

在協議countable中定義了函數clojure.core/count和方法count。就像警告所說:通過創建一個名爲count的方法的接口,將名稱爲count的別名覆蓋爲clojure.core/count

通過(range 5)返回的LazySeq對象沒有實現你的countable協議。你仍然可以用(clojure.core/count (range 5))來計算它。

你可能想要做的是實現clojure.lang.Counted接口而不是你自己的接口。

+1

「你可能想要做的是實現clojure.lang.Counted界面,而不是你自己的界面。」 - 不幸的是OP想要將協議擴展到現有的Java類 - 沒有跡象表明該類可以修改。 – Alex

+0

然後他應該通過defrecord或使用reify創建一個Clojure包裝。 –

+0

對不起@lgrapenthin我選中你的解決方案,因爲我不能修改Java類和,defrecord或具體化不工作,要麼怎麼一回事,因爲有一些我不創建實例時間:( – tangrammer

0

感謝所有,

我在這裏公佈的2可行的解決方案我已經達到了這個情況,感謝所有您的意見

在任何情況下,我不得不改變功能

看來,multimethods也(我還不確定性能後果...)可以解決這裏的表達問題

(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的互操作sintaxis影響(參數定義了FN,而不是相反的) -

相關問題