【问题标题】:Maps and records equality in ClojureClojure 中的映射和记录相等性
【发布时间】:2012-03-03 00:28:41
【问题描述】:

我发现 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,我发现它们真的很混乱。

【问题讨论】:

    标签: map clojure record equality


    【解决方案1】:

    来自defrecord 的文档字符串:

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

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

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

    【讨论】:

    • 为什么 PersistentArrayMap 和 PersistentHashMap 的实例等于 = then 既然 type 函数表明它们不是同一个类型?
    • defrecord 的文档字符串中声明了“基于类型和值的 =" 承诺并适用于记录。另一方面,常规映射应该参与基于值的 = 方案,并且它们确实参与到 (= (hash-map :foo 1 :bar 2) (sorted-map :foo 1 :bar 2))(= (java.util.HashMap. {:foo 1 :bar 2}) {:foo 1 :bar 2}) 都是 true 的程度。
    【解决方案2】:

    PersistentArrayMapPersistentHashMap 在概念上是相同的——随着 ArrayMap 的增长,出于性能原因,它会自动转换为 HashMap。用户级代码一般不应试图区分两者。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多