2014-10-29 56 views
4

如果我有一個自定義類型,並使用它創建具有完全相同值的兩個單獨實例,那麼可以使用什麼方法來確定這兩個事物是等價的? identical?===似乎不起作用。我預料會有一些協議來設置類型比較。最終,我希望它能夠將相同的事物添加到一個集合中。Clojure值相等並設置

(deftype Ref [id]) 
(def r1 (->Ref 1)) 
(def r2 (->Ref 1)) 
(= r1 r2) ;false rather than true 
(def refs #{}) 
(conj refs r1 r2) ;adds both, but want one 

=作品與defrecord,但我會如何定義=deftype

+1

一件小事:'=='僅爲數字數據定義'user>(==:a:a)=> ClassCastException clojure.lang.Keyword不能轉換爲java.lang.Number clojure.lang.Numbers .equiv(Numbers.java:206)' – noisesmith 2014-10-29 04:45:55

回答

4

defrecord已經有這種行爲你描述:

user=> (defrecord Point [x y]) 
user.Point 
user=> (= (Point. 0 0) (Point. 0 0)) 
true 
user=> (into #{} [(Point. 0 0) (Point. 1 1) (Point. 0 0)]) 
#{#user.Point{:x 1, :y 1} #user.Point{:x 0, :y 0}} 

deftype,另一方面不執行默認Clojure的常用結構相等(也不是defstruct爲我們提供了可讀取的打印方法):

user=> (deftype Pair [a b]) 
user.Pair 
user=> (= (Pair. 0 0) (Pair. 0 0)) 
false 
user=> (into #{} [(Pair. 0 0) (Pair. 1 1) (Pair. 0 0)]) 
#{#<Pair [email protected]> #<Pair [email protected]> #<Pair [email protected]>} 

也就是說,deftype功能更強大,您可以使其表現得像我們喜歡的:

user=> (deftype Tuple [a b] 
     Object 
     (equals [this other] 
      (and (= (.a this) (.a other)) 
       (= (.b this) (.b other)))) 
     (toString [this] 
      (str "<" (.a this) "," (.b this) ">")) 
     (hashCode [this] 
      (hash {:a (.a this) :b (.b this)})) 
     Comparable 
     (compareTo [this that] 
      (compare [(.a this) (.b this)] 
        [(.a that) (.b that)]))) 
user.Tuple 
user=> (= (Tuple. 0 0) (Tuple. 0 0)) 
true 
user=> (into #{} [(Tuple. 0 0) (Tuple. 1 1) (Tuple. 0 0)]) 
#{#<Tuple <0,0>> #<Tuple <1,1>>} 
6

在你DEFTYPE,延長Object和實施equals給他們平等的語義:

(deftype Ref [id] 
    Object 
    (equals [_ other] (= id (.id other)))) 

集遏制,還需要哈希碼支持:

(deftype Ref [id] 
    Object 
    (equals [_ other] (= id (.id other))) 
    (hashCode [_] id) 
    clojure.lang.IHashEq 
    (hasheq [_] id)) 

我實現了兩個Java的哈希支持和Clojure的hasheq在那裏支持。實施IHashEq會更快。

+0

'hash-set',等於不足(我試過了),'hashCode'也是需要的。還沒有完成 – noisesmith 2014-10-29 04:37:16

+0

輸入...現在:) – 2014-10-29 04:46:19