Scala in Depth在mutability
和equality
上提供了此代码。
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
编辑在我看来,这个例子显示了命令式编程的复杂性(差)。
答案 0 :(得分:6)
因为Map仍然使用x
来测试相等性。
以下是发生的事情:
x
作为键插入地图,此时的hashCode为#x。大。x
上更改了某些值,#x现已消失,新的hashCode为#x'。x
相关联的值。地图获取hashCode:#x'。它在地图中不存在(因为在插入时它是#x)。z
原来拥有的相同值创建x
。z
相关联的值。地图找到了z
的hashCode的值(因为它是#x),但随后在equals
和z
上调用x
(您用于插入的false
在第一步中的价值)。你移动x
后得到equals
! 映射保留对密钥实例的引用,并在get
时使用它来测试{{1}},但它永远不会重新计算hashCode。