2012-02-10 53 views
6

我發現Clojure的行爲混淆了地圖和記錄之間的平等。在第一個例子中,我們有兩種結構相同的不同類型。平等=函數返回true:Clojure地圖和記錄的平等

user> (defn make-one-map 
     [] 
     {:a "a" :b "b"}) 
#'user/make-one-map 
user> (def m1 (make-one-map)) 
#'user/m1 
user> m1 
{:a "a", :b "b"} 
user> (def m2 {:a "a" :b "b"}) 
#'user/m2 
user> m2 
{:a "a", :b "b"} 
user> (= m1 m2) 
true 
user> (type m1) 
clojure.lang.PersistentArrayMap 
user> (type m2) 
clojure.lang.PersistentHashMap 

在第二個例子中,我們有一個HashMap和它在結構上相當於一個記錄,但該=函數返回false:

user> (defrecord Titi [a b]) 
user.Titi 
user> (def titi (Titi. 1 2)) 
#'user/titi 
user> titi 
#user.Titi{:a 1, :b 2} 
user> (= titi {:a 1 :b 2}) 
false 

爲什麼不同之處?我使用的是Clojure 1.3,我發現它們很混亂。

回答

14

從文檔字符串爲defrecord

此外,defrecord將定義類型 - 值基於=,並且將 定義的Java .hashCode和.equals與合同 java.util中一致的。地圖。

因此,當使用=時,需要考慮類型。你可以使用.equals代替:

user> (.equals titi {:a 1 :b 2}) 
true 
+0

爲什麼PersistentArrayMap和PersistentHashMap的實例等於= then,因爲type函數指示它們不是同一類型? – z1naOK9nu8iY5A 2012-02-10 19:44:04

+7

「defrecord」的文檔字符串中陳述了「type-and-value-based =」的承諾並適用於記錄。另一方面,常規地圖應該參與基於價值的方案,並且它們的確如此:「(=(hash-map:foo 1:bar 2)(sorted-map:foo 1: bar 2))'和'(=(java.util.HashMap。{:foo 1:bar 2}){:foo 1:bar 2})'都是'true'。 – 2012-02-11 00:11:20

8

一個PersistentArrayMapPersistentHashMap在概念上是相同的 - 作爲ArrayMap的增長,它會自動地轉化爲性能原因HashMap中。用戶級代碼通常不應試圖區分這兩者。

另一方面,A defrecord數據類型與其他地圖不同。它是一個獨立的類型,可以實現完全不同的接口,不應該被其他形式的地圖自動替換。它在概念上與普通地圖不相同,因此=返回false。