覆盖Clojure记录的等于

时间:2014-04-16 22:29:07

标签: clojure interop

我有一个记录,其中一个字段的类型为byte[]。由于没有为数组定义Clojure相等,我们有:

(defrecord Record [^bytes field])
(def rec1 (->Record (byte-array (map byte "abc"))))
(def rec2 (->Record (byte-array (map byte "abc"))))

(= rec1 rec2)
; => false

当然,这是不可接受的。

现在,我们确实有java.util.Arrays.equals来定义数组的正确等式。因为=对于其他Clojure对象非常有效,所以每次比较我的Record类型,类型包括该类型等时,我都不想使用interop。

是否可以覆盖记录的equals函数来处理数组?


我尝试了以下内容:

(defrecord Record [^bytes field])
  Object
    (equals [this other] (Arrays/equals this other)))

但我收到错误,“重复的方法名称和签名”。

2 个答案:

答案 0 :(得分:7)

数组在clojure中比较相同的原因是因为它们可以随时改变,并且相等的对象应该保持相等。想象一下像{rec1 1}这样的地图。如果您的两个对象相等,我应该能够在其中查找rec2并找到答案1。但如果有人(aset (:field rec2) 1 3),则rec2突然发生了变化,并且不再等于rec1!这不是应该发生的事情,所以clojure说他们并不相等。

这类似于原子和其他可变容器的等式语义:因为两个可变容器(atoms,或arrays )具有相同的内容现在并不意味着容器本身是相等的。当某人修改其中一个时,这种脆弱的平等可能随时发生变化。同样,你的两个数组可能随时变得不相等;这意味着,实际上,它们根本就不相同。

答案 1 :(得分:2)

数组是可变的,因此不是。 Clojure相等性取决于组合值在记录等复合事物中的不变性。数组是脏的可变事物 - 作为一般起点,不要这样做。

如果你真的想要使用数组并且需要自定义语义,请使用deftype并定义自己的equals方法。但是你需要知道,就Clojure而言,你是“在地图上” - 这不是“正常的”Clojure。

相关问题