canEqual () в scala.Равна черта
из исходного кода scala/Equals.scala
(здесь):
package scala
trait Equals extends scala.Any {
def canEqual(that: scala.Any): scala.Boolean
def equals(that: scala.Any): scala.Boolean
}
в документации говорится:
метод, который должен вызываться из каждого хорошо разработанного метода equals, открытого для переопределения в подклассе.
я случайно выбрал класс, который расширяется scala.Equals
и который достаточно прост, чтобы понять. Я выбрал scala.Tuple2[+T1, +T2]
, что расширяет признак scala.Product[T1, T2]
, что в свою очередь расширяет черта scala.Product
, который в поворот расширяет признак scala.Equals
.
к сожалению, кажется, что потому что scala.Tuple2
это класс case, the canEqual()
и equals()
методы генерируются автоматически и поэтому не могут быть найдены в исходном коде scala/Tuple2.scala
(здесь).
мои вопросы:
- когда это хорошее время, чтобы расширить черта
scala.Equals
? - как следует ?
- что самое лучшее практика (или шаблон) для использования
canEqual()
наequals()
?
спасибо заранее!
PS: Если это имеет значение, я использую Scala 2.11.7.
1 ответов
The canEquals
метод используется для покрытия ожидания, что equals
должен быть симметричным - то есть, если (и только если) a.equals(b)
истинно, то b.equals(a)
также должно быть истинным. Проблемы с этим могут возникнуть при сравнении экземпляра класса с экземпляром подкласса. Например.
class Animal(numLegs: Int, isCarnivore: Boolean) {
def equals(other: Any) = other match {
case that: Animal =>
this.numLegs == that.numLegs &&
this.isCarnivore == that.isCarnivore
case _ => false
}
}
class Dog(numLegs: Int, isCarnivore: Boolean, breed: String) extends Animal(numLegs, isCarnivore) {
def equals(other: Any) = other match {
case that: Dog =>
this.numLegs == that.numLegs &&
this.isCarnivore == that.isCarnivore &&
this.breed == that.breed
case _ => false
}
}
val cecil = new Animal(4, true)
val bruce = new Dog(4, true, "Boxer")
cecil.equals(bruce) // true
bruce.equals(cecil) // false - cecil isn't a Dog!
чтобы исправить это, убедитесь, что два объекта имеют один и тот же (sub-)тип, используя canEqual
в определении equals
:
class Animal(numLegs: Int, isCarnivore: Boolean) {
def canEqual(other: Any) = other.isInstanceOf[Animal]
def equals(other: Any) = other match {
case that: Animal =>
that.canEqual(this) &&
this.numLegs == that.numLegs &&
this.isCarnivore == that.isCarnivore
case _ => false
}
}
class Dog(numLegs: Int, isCarnivore: Boolean, breed: String) extends Animal(numLegs, isCarnivore) {
def canEqual(other: Any) = other.isInstanceOf[Dog]
def equals(other: Any) = other match {
case that: Dog =>
that.canEqual(this) &&
this.numLegs == that.numLegs &&
this.isCarnivore == that.isCarnivore &&
this.breed == that.breed
case _ => false
}
}
val cecil = new Animal(4, true)
val bruce = new Dog(4, true, "Boxer")
cecil.equals(bruce) // false - call to bruce.canEqual(cecil) returns false
bruce.equals(cecil) // false