问题描述
对于两个逻辑上相等的 case 类实例,Equals 无法正常工作。 请在下面找到简化的案例类:-
case class Item(name : String)
case class Basket(items : Array[Item],bills : Map[Int,Int])
def createBasketInstance() : Basket = {
val maggi = Item("milk")
val coffee = Item("coffee")
val bills1 = Map(1 -> 20,2 -> 75)
Basket( Array(maggi,coffee),bills1 )
}
val basket1 = createBasketInstance()
val basket2 = createBasketInstance()
basket1.equals(basket2) 的预期结果为真,但实际打印为假。
scalafiddle 链接:https://scalafiddle.io/sf/iJRKnMk/0
请找到附加的屏幕截图,以确认使用 Scalatest 进行相等比较。
解决方法
这与 equals
的默认 case classes
无关,而是 Arrays
的默认 Lists
(这是您应该使用 Arrays
而不是 { {1}}顺便说一句)
在 Scala 中数组只是普通的 Java 数组,Java 中的数组被特殊处理(因为 JVM)
即使是简单的
Array(1,2,3) == Array(1,3)
将返回 false。
为什么?因为数组继承了 Object.equals
方法的 equals
只比较了数组引用,而不是它们的内容。
我知道这听起来没有那么糟糕,但相信情况会变得更糟。
您可能认为简单地将数组分配给一个值就可以解决问题,对吗?好吧,它没有。以下也将失败...
def createBasketInstance() : Basket = {
val maggi = Item("milk")
val coffee = Item("coffee")
val arr = Array(maggi,coffee)
val bills1 = Map(1 -> 20,2 -> 75)
Basket( arr,bills1 )
}
因为这个函数的不同调用的调用栈不能共享引用,因此即使底层内容相同,每次函数调用都会创建一个新的引用。
你是如何解决这个问题的?
-
java.utils.Arrays
中有一个名为Arrays.equals
的方法可以进行深度比较。您可以override
并构造它,以便比较使用Arrays.equals
。您可能还需要覆盖hashCode
-
编写从
Array
到几乎任何其他集合的隐式转换 -
首先不要使用数组。
我想说 #3 是解决这个问题的方法