2012-02-10 26 views
6

地図とレコードの平等性に関するClojureの動作が混乱していることがわかりました。この最初の例では、構造的に等しい2つの異なるタイプがあります。Clojureのマップと等価性

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 

はなぜ違います:私たちはハッシュマップと構造的に同等であるが、記録=関数はfalseを返しますを持っている2番目の例では

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 

:平等=関数はtrueを返しますか?私はClojure 1.3を使用しており、私はそれらが本当に混乱していることがわかりました。 defrecordのdocstringから

答えて

14

:また

、defrecordは、タイプおよび値に基づく=を定義し、 はjava.utilの契約と一致するJava .hashCodeと.equalsを定義します。地図。

したがって、=を使用する場合、タイプが考慮されます。あなたは代わりに.equalsを使用することもできます。

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

PersistentArrayMapとPersistentHashMapのインスタンスは、型関数が同じ型ではないことを示すため、=と等しいのはなぜですか? – z1naOK9nu8iY5A

+7

"型と価値に基づく="約束は 'defrecord'の文書文字列に記述され、レコードに適用されます。一方、正規マップは、値ベースの=スキームに参加することになっていて、 '(=(ハッシュマップ:foo 1:バー2)(ソートマップ:foo 1: bar 2)) 'と'(=(java.util.HashMap。{:foo 1:bar 2}){{foo 1:bar 2}) 'はどちらも' true'です。 –

8

PersistentArrayMapPersistentHashMapは概念的には同じです - ArrayMapの成長に合わせて、自動的にパフォーマンス上の理由のHashMapに変換されます。ユーザーレベルのコードでは、一般的に2つのコードを区別する必要はありません。

defrecordのデータ型は、他のマップと同じではありません。完全に異なるインターフェースを実装する可能性のある別個のタイプであり、他の形式のマップによって自動的に置き換えられるべきではありません。概念的には法線マップには等しくないため、=はfalseを返します。