Scala 多态判等问题 canEquals

Scala 虽然语法看起来似乎很复杂,实际上在很多方面追求更简单的设计,核心规则非常少。

在工程项目中,好的判等方法很重要。最佳实践如下:

  • 在做深度判等前先做引用判等
  • 复杂的类,引用判等之后优先考虑 hashCode 判等
  • 较为简单的类,可以考虑直接用类的属性判等

Java 中多态判等,需要考虑很多问题:

object CanEquals {
def main(args: Array[String]) {
val a = new InstantaneousTime {
override val repr: Int = 2
}

val b = new Event {
override val name: String = "test"
override val repr: Int = 2
}
println(a == b) // true 多态的判等问题
}

trait InstantaneousTime {
val repr: Int

override def equals(obj: scala.Any): Boolean = obj match {
case that: InstantaneousTime =>
if (this eq that) true
else (that.## == this.##) && (repr == that.repr)
case _ => false
}

override def hashCode(): Int = repr.##
}

trait Event extends InstantaneousTime {
val name: String

override def equals(obj: Any): Boolean = obj match {
case that: Event =>
if (this eq that) true
else (repr == that.repr) && (name == that.name)
case _ => false
}
}

从上面的示例可以看出,多态判等很容易出错;我们再看一下 Scala 通过引入一个特质 Equals来简化这个问题

object CanEquals {
def main(args: Array[String]) {
val a = new InstantaneousTime {
override val repr: Int = 2
}

val b = new Event {
override val name: String = "test"
override val repr: Int = 2
}
println(a == b) // false 正确判断
}

trait InstantaneousTime extends Equals {
val repr: Int

// 允许任意子类
override def canEqual(that: Any): Boolean = that.isInstanceOf[InstantaneousTime]

override def equals(obj: scala.Any): Boolean = obj match {
case that: InstantaneousTime =>
if (this eq that) true
else (that.## == this.##) && (that canEqual this) && (repr == that.repr) // 调用另一个对象的 canEquals
case _ => false
}

override def hashCode(): Int = repr.##
}

trait Event extends InstantaneousTime1 {
val name: String

// 允许任意子类
override def canEqual(that: Any): Boolean = that.isInstanceOf[Event]

override def equals(obj: Any): Boolean = obj match {
case that: Event =>
if (this eq that) true
else (repr == that.repr) && (name == that.name)
case _ => false
}


- - - - - - - - End Thank For Your Reading - - - - - - - -