Проблема вашего примера в том, что вы переопределяете только метод equals
анонимного класса, частью которого вы определяете свой конкретный кортеж. Давайте внимательнее посмотрим, что вы делаете, выполняя приведенный здесь код.
val p = new Pair(1, 2) {
override def equals(obj:Any) = {
obj.isInstanceOf[(Int, Int)] && obj.asInstanceOf[(Int, Int)]._1 == this._1
}
}
То, что здесь делает Scala, - это создание нового анонимного класса, который расширяет Pair
и переопределяет его равные. Так что это эквивалентно выполнению следующего кода:
class Foo extends Pair(1,2) {
override def equals(obj:Any) = {
obj.isInstanceOf[(Int, Int)] && obj.asInstanceOf[(Int, Int)]._1 == this._1
}
}
val p = new Foo
И здесь вы можете точно увидеть, в чем проблема! Определение equals
не является симметричным. p == (1,1)
оценивается в true
, а (1,1) == p
оценивается в false
! Это потому, что первое эквивалентно p.equals((1,1))
, а второе эквивалентно (1,1).equals(p)
. В приведенном вами примере это не работает, потому что объект в данном случае сравнивается с сопоставляемым объектом, а не наоборот. Следовательно, как вы указали, Pair.unapply(p).get == (1, 1)
оценивается в true
, однако (1,1) == Pair.unapply(p).get
оценивается в false
, и кажется, что последний используется при сопоставлении.
Однако в любом случае создание не симметричных равных - это действительно очень плохая идея , поскольку выполнение кода зависит от порядка, в котором вы сравниваете объекты. Кроме того, определенные вами равенства имеют Еще одна проблема - это ошибка с ошибкой, когда вы пытаетесь сравнить p
с любым Pair
, который не типа (Int, Int)
. Это происходит потому, что после стирания типа (то есть, как JVM реализует обобщения), Pair
больше не параметризуется типами его составляющих. Следовательно, (Int, Int)
имеет точно такой же тип, как и (String, String)
, и, следовательно, следующий код завершится ошибкой:
p == ("foo", "bar")
, поскольку Скала попытается разыграть (String, String)
до (Int, Int)
.
Если вы хотите реализовать эту функцию, самое простое, что вы можете сделать, это использовать шаблон pimp my library, pimping a Pair
. Однако вы не должны вызывать свой метод equals
. Назовите это как-нибудь еще, например ~=
. Я должен идти сейчас, однако, когда я вернусь, я мог бы дать вам код для этого. Это довольно легко. Вы должны посмотреть на реализацию equals
в паре и удалить часть, которая сравнивает второй аргумент:)