我有一个记录,其中一个字段的类型为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)))
但我收到错误,“重复的方法名称和签名”。
答案 0 :(得分:7)
数组在clojure中比较相同的原因是因为它们可以随时改变,并且相等的对象应该保持相等。想象一下像{rec1 1}
这样的地图。如果您的两个对象相等,我应该能够在其中查找rec2
并找到答案1
。但如果有人(aset (:field rec2) 1 3)
,则rec2
突然发生了变化,并且不再等于rec1
!这不是应该发生的事情,所以clojure说他们并不相等。
这类似于原子和其他可变容器的等式语义:因为两个可变容器(atoms,或arrays )具有相同的内容现在并不意味着容器本身是相等的。当某人修改其中一个时,这种脆弱的平等可能随时发生变化。同样,你的两个数组可能随时变得不相等;这意味着,实际上,它们根本就不相同。
答案 1 :(得分:2)
数组是可变的,因此不是值。 Clojure相等性取决于组合值在记录等复合事物中的不变性。数组是脏的可变事物 - 作为一般起点,不要这样做。
如果你真的想要使用数组并且需要自定义语义,请使用deftype并定义自己的equals方法。但是你需要知道,就Clojure而言,你是“在地图上” - 这不是“正常的”Clojure。