2012-02-10 37 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。