Карты и записи равенства в Clojure - PullRequest
7 голосов
/ 10 февраля 2012

Я обнаружил, что поведение Clojure сбивает с толку в отношении равенства между картами и записями. В этом первом примере у нас есть два разных типа, которые структурно равны. Функция равенства = возвращает true:

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

Во втором примере у нас есть хэш-карта и запись, которые являются структурно эквивалентными, но функция = возвращает 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, и я нашел их действительно запутанными.

Ответы [ 2 ]

15 голосов
/ 10 февраля 2012

Из строки документации для defrecord:

Кроме того, defrecord определит тип и значение на основе = и определит Java .hashCode и .equals в соответствии с контрактом для Java.util.Map.

Таким образом, при использовании =, тип учитывается.Вы можете использовать .equals вместо:

user> (.equals titi {:a 1 :b 2})
true
8 голосов
/ 10 февраля 2012

a PersistentArrayMap и PersistentHashMap концептуально совпадают - по мере роста ArrayMap он автоматически преобразуется в HashMap по соображениям производительности.Код уровня пользователя, как правило, не должен пытаться различать два.

Тип данных defrecord, с другой стороны, отличается от типа других карт.Это отдельный тип, который может реализовывать совершенно разные интерфейсы и не должен автоматически заменяться какой-либо другой формой карты.Концептуально он не равен карте нормалей, поэтому = возвращает false.

...