2013-12-17 8 views
2

Scala in Depth представляет этот код на mutability и equality.Scala Equality and HashCode

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 = [email protected] 
scala> val y = new Point2(1,2) 
y: Point2 = [email protected] 
scala> val z = new Point2(1,1) 
z: Point2 = [email protected] 

В настоящее время создается HashMap.

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

scala> x.move(1,1) 

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

Я понимаю, что map(x) будет возвращать NoSuchElementException так x мутировал. x's hashCode получает пересчет из-за мутации x.move(1,1). В результате при проверке, находится ли x в map, ни один из s карты не соответствует x 's new hashCode.

scala> map(x) 
java.util.NoSuchElementException: key not found: [email protected] 
... 

С z равно (значение) первоначально вставлен x из HashMap, а также hashCode, почему выбрасывается исключение?

scala> map(z) 
java.util.NoSuchElementException: key not found: [email protected] 

EDIT Этот пример, на мой взгляд, показывает сложность (плохой) от императивного программирования.

+0

Вы уверены, что это код? Не выглядит правильным. –

+0

Я получил отсюда - http://www.manning.com/suereth/SiD-Sample02.pdf –

ответ

5

Поскольку карта по-прежнему использует x для проверки равенства.

Вот что происходит:

  • вставки в карту, используя x как ключ, хэш-код в это время #x. Отлично.
  • вы меняете некоторые значения на x, #x теперь ушел, новый хэш-код - #x '.
  • Вы пытаетесь найти значение, связанное с x на карте. Карта получает hashCode: #x '. Он не существует на карте (так как во время вставки это было #x).
  • вы создаете z с теми же значениями x изначально был.
  • Вы просматриваете значение, связанное с z. На карте найдено значение для hashCode z (так как это #x), но затем вызывает equals по z и x (тот же экземпляр, который вы использовали для ввода значения на первом этапе). И вы получите false, так как вы переместили x!

Карта хранит ссылку на экземпляр ключа, и использовать его для проверки equals когда вы get, но он никогда не будет повторно вычисляет хэш-код.

+0

Thx. Моя прежняя путаница возникла из-за непонятности (1) hashCode вычисляется один раз для HashMap и ** никогда ** изменяется, и (2) эта карта содержит ссылку на 'x', которая является« неизменной »ссылкой на' mutable' структура данных.Изменение структуры данных, на которую 'x' ponts изменят« map »на соответствующий объект' key' –

+0

@KevinMeredith, это не сразу очевидно, но это имеет смысл, поскольку 2 абсолютно несвязанных (например, не одинаковых типа) объектов может закончиться тем же хэш-кодом, что и карта должна выполнить другую проверку, чтобы убедиться, что она идентифицировала правильный ключ. Я читал книгу, и если я правильно помню, это не особенно хорошо объяснено :) – vptheron