在Clojure中映射和记录相等性

z1n*_*Y5A 7 equality record clojure map

我发现Clojure的行为混淆了地图和记录之间的平等.在第一个例子中,我们有两种结构相同的不同类型.equality =函数返回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
Run Code Online (Sandbox Code Playgroud)

在第二个例子中,我们有一个hashmap和一个记录,它们在结构上是等价的,但是= function返回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
Run Code Online (Sandbox Code Playgroud)

为什么会有差异?我正在使用Clojure 1.3,我发现它们真的令人困惑.

Jus*_*mer 15

来自docstring defrecord:

此外,defrecord将定义基于类型和值的=,并将定义Java .hashCode和.equals与java.util.Map的契约一致.

因此,在使用时=,会考虑类型.你可以.equals改用:

user> (.equals titi {:a 1 :b 2})
true
Run Code Online (Sandbox Code Playgroud)

  • "type-and-value-based ="承诺在`defrecord`的docstring中说明并适用于记录.另一方面,常规地图应该参与基于值的方案,他们确实参与了`(=(hash-map:foo 1:bar 2)(sorted-map:foo 1: bar 2))`和`(=(java.util.HashMap.{:foo 1:bar 2}){:foo 1:bar 2})`都是'true`. (7认同)

Ret*_*ief 8

a PersistentArrayMap和a PersistentHashMap在概念上是相同的 - 随着ArrayMap的增长,出于性能原因,它将自动转换为HashMap.用户级代码通常不应该尝试区分这两者.

defrecord数据类型,在另一方面,是不一样的其他地图之一.它是一个单独的类型,可以实现完全不同的接口,不应该被其他形式的地图自动替换.它在概念上不等于法线贴图,因此=返回false.