2012-02-10 12 views
6

Ho trovato il comportamento di Clojure che confonde l'uguaglianza tra mappe e record. In questo primo esempio, abbiamo due diversi tipi che sono strutturalmente uguali. L'uguaglianza = funzione restituisce true:Mappe e record di uguaglianza in 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 

Nel secondo esempio abbiamo un HashMap e un record che sono strutturalmente equivalenti ma la funzione = restituisce 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 

Perché sono le differenze? Sto usando Clojure 1.3 e li ho trovati davvero confusi.

risposta

14

Dal docstring per defrecord:

Inoltre, defrecord definirà = tipo-e-valore-base, e sarà definito Java .hashCode e .equals coerente con il contratto per java.util .Carta geografica.

Quindi, quando si utilizza =, viene preso in considerazione il tipo. Si potrebbe utilizzare .equals invece:

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

Perché le istanze di PersistentArrayMap e PersistentHashMap sono uguali a = allora poiché la funzione tipo indica che non sono dello stesso tipo? – z1naOK9nu8iY5A

+7

La promessa "type-and-value-based =" è indicata nella docstring di 'defrecord' e si applica ai record. Le mappe regolari, d'altro canto, dovrebbero partecipare a uno schema basato sul valore, e lo fanno, al punto che '(= (hash-map: foo 1: bar 2) (mappa ordinata: foo 1: bar 2)) 'e' (= (java.util.HashMap. {: foo 1: bar 2}) {: foo 1: bar 2}) 'sono entrambi' true'. –

8

un PersistentArrayMap e un PersistentHashMap sono concettualmente lo stesso - come cresce l'ArrayMap, verrà automaticamente ottenere convertito in un HashMap per motivi di prestazioni. Il codice a livello utente non dovrebbe generalmente cercare di distinguere tra i due.

Un tipo di dati defrecord, al contrario, non è uguale a una delle altre mappe. È un tipo separato che può implementare interfacce completamente diverse e non dovrebbe essere automaticamente sostituito da qualche altra forma di mappa. Non è concettualmente uguale a una mappa normale, quindi = restituisce false.

Problemi correlati