2012-02-10 13 views
6

Encontré el comportamiento de Clojure confuso en cuanto a la igualdad entre mapas y registros. En este primer ejemplo, tenemos dos tipos diferentes que son estructuralmente iguales. La igualdad = función devuelve verdadero:Igualación de mapas y registros en 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 

En el segundo ejemplo tenemos un mapa hash y un registro que son estructuralmente equivalentes, pero la función = devuelve falso:

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 

¿Por qué son las diferencias? Estoy usando Clojure 1.3 y los encontré realmente confusos.

Respuesta

14

Desde la cadena de documentación para defrecord:

Además, defrecord definirá en base = tipo-y-valor, y tendrá definido Java .hashCode y .equals consistente con el contrato para java.util .Mapa.

Por lo tanto, cuando se usa =, se tiene en cuenta el tipo. Usted podría utilizar en lugar .equals:

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

¿Por qué son iguales las instancias de PersistentArrayMap y PersistentHashMap con = dado que la función de tipo indica que no son del mismo tipo? – z1naOK9nu8iY5A

+7

La promesa "type-and-value-based =" se establece en el docstring de 'defrecord' y se aplica a los registros. Por otro lado, se supone que los mapas regulares participan en un esquema = basado en el valor, y lo hacen, hasta el punto en que '(= (hash-map: foo 1: bar 2) (ordenado-mapa: foo 1: bar 2)) 'y' (= (java.util.HashMap. {: foo 1: bar 2}) {: foo 1: bar 2}) 'son ambos' verdaderos'. –

8

un PersistentArrayMap y una PersistentHashMap son conceptualmente el mismo - a medida que crece la ArrayMap, se obtendrá automáticamente convertido a un HashMap por razones de rendimiento. El código de nivel de usuario generalmente no debe tratar de distinguir entre los dos.

Un tipo de datos defrecord, por otro lado, no es lo mismo que uno de los otros mapas. Es un tipo separado que puede implementar interfaces completamente diferentes y no debe reemplazarse automáticamente por otra forma de mapa. No es conceptualmente igual a un mapa normal, por lo que = devuelve falso.

Cuestiones relacionadas