Scala Equality和HashCode

时间:2013-12-17 19:23:08

标签: scala hashcode equality

Scala in Depthmutabilityequality上提供了此代码。

class Point2(var x: Int, var y: Int) extends Equals {
def move(mx: Int, my: Int) : Unit = {
  x = x + mx
  y = y + my
}
override def hashCode(): Int = y + (31*x)

def canEqual(that: Any): Boolean = that match {
  case p: Point2 => true
  case _ => false
}
override def equals(that: Any): Boolean = {
def strictEquals(other: Point2) =
  this.x == other.x && this.y == other.y
  that match {
    case a: AnyRef if this eq a => true
    case p: Point2 => (p canEqual this) && strictEquals(p)
     case _ => false
  }
}
}

然后,它执行评估。

scala> val x = new Point2(1,1)
x: Point2 = Point2@20
scala> val y = new Point2(1,2)
y: Point2 = Point2@21
scala> val z = new Point2(1,1)
z: Point2 = Point2@20

接下来,创建HashMap

scala> val map = HashMap(x -> "HAI", y -> "WORLD")
map: scala.collection.immutable.HashMap[Point2,java.lang.String] =
Map((Point2@21,WORLD), (Point2@20,HAI))

scala> x.move(1,1)

scala> map(y)
res9: java.lang.String = WORLD

我了解map(x)会因NoSuchElementException发生变异而返回x。由于x的变异,x.move(1,1的hashCode被重新计算。因此,在检查x中是否有map时,地图的hashCode都不匹配x的新hashCode

scala> map(x)
java.util.NoSuchElementException: key not found: Point2@40
...

由于z等于(值)最初插入的x HashMap以及hashCode,为什么会抛出异常?

scala> map(z)
java.util.NoSuchElementException: key not found: Point2@20

编辑在我看来,这个例子显示了命令式编程的复杂性(差)。

1 个答案:

答案 0 :(得分:6)

因为Map仍然使用x来测试相等性。

以下是发生的事情:

  • 使用x作为键插入地图,此时的hashCode为#x。大。
  • 您在x上更改了某些值,#x现已消失,新的hashCode为#x'。
  • 您尝试在地图中查找与x相关联的值。地图获取hashCode:#x'。它在地图中不存在(因为在插入时它是#x)。
  • 您使用z原来拥有的相同值创建x
  • 您查找与z相关联的值。地图找到了z的hashCode的值(因为它是#x),但随后在equalsz上调用x(您用于插入的false在第一步中的价值)。你移动x后得到equals

映射保留对密钥实例的引用,并在get时使用它来测试{{1}},但它永远不会重新计算hashCode。