问题描述
来自源代码scala/Equals.scala
(此处 ):
package scala
trait Equals extends scala.Any {
def canEqual(that: scala.Any): scala.Boolean
def equals(that: scala.Any): scala.Boolean
}
在文档中说:
我随机选择了一个扩展scala.Equals
的类,它很容易理解.我选择了scala.Tuple2[+T1, +T2]
,它扩展了特征scala.Product[T1, T2]
,又扩展了特征scala.Product
,又扩展了特征scala.Equals
.
I randomly picked a class which extends scala.Equals
and which is simple enough to understand. I picked scala.Tuple2[+T1, +T2]
, which extends the trait scala.Product[T1, T2]
, which in turn extends the trait scala.Product
, which in turn extends the trait scala.Equals
.
不幸的是,似乎因为scala.Tuple2
是 case类,所以canEqual()
和equals()
方法是自动生成的,因此无法在源代码scala/Tuple2.scala
中找到( 此处).
Unfortunately, it seems that because scala.Tuple2
is a case class, the canEqual()
and equals()
methods are automatically generated and therefore could not be found in the source code scala/Tuple2.scala
(here).
我的问题是:
- 何时扩展性状
scala.Equals
的好时机? -
canEqual()
应该如何实施? - 在
equals()
中使用canEqual()
的最佳实践(或样板)是什么?
- When is it a good time to extend the trait
scala.Equals
? - How should
canEqual()
be implemented? - What are the best practices (or boilerplate) to use
canEqual()
inequals()
?
提前谢谢!
PS:如果有关系的话,我正在使用Scala 2.11.7.
PS: In case if it matters, I'm using Scala 2.11.7.
推荐答案
canEquals
方法用于满足以下要求:equals
应该是对称的-即,(且仅)当a.equals(b)
为true时,则b.equals(a)
也应为true.将类的实例与子类的实例进行比较时,可能会出现问题.例如
The canEquals
method is used to cover the expectation that equals
should be symmetric - that is, if (and only if) a.equals(b)
is true, then b.equals(a)
should also be true. Problems with this can arise when comparing an instance of a class with an instance of a sub-class. Eg.
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!
要解决此问题,请在equals
的定义中使用canEqual
确保两个实体具有相同(子)类型:
To fix this, ensure the two entities are of the same (sub-)type using canEqual
in the definition of 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
这篇关于scala.Equals特性中的canEqual()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!