Scala完全匹配类(不扩展)

时间:2014-05-07 16:03:23

标签: scala match equals matching

问题
在Scala中,有没有办法编写一个match子句,它通过它的类匹配一个对象,但是不匹配任何扩展类?

动机
它可能看起来很迂腐..它是 无论如何,当我看到IntelliJ生成的equals函数时,我想到了它:

class Position(val x: Float, val y: Float) {

  def canEqual(other: Any): Boolean = other.isInstanceOf[Position]

  override def equals(other: Any): Boolean = other match {
    case that: Position =>
      (that canEqual this) &&
        x == that.x &&
        y == that.y
    case _ => false
  }

  // generated hashCode omitted for brevity

}

在这里,我们可以看到other类匹配为Position,然后canEqual用于在匹配上设置上限。也就是说,other仍可以是Position3D,即使Positionx坐标相同,也不应等于y

这是有道理的,但我想知道某种形式的Scala巫术是否会让我们明确地匹配Position类而不是子类。

2 个答案:

答案 0 :(得分:1)

尝试:

other match {
    case that: Position if that.getClass == classOf[Postion] => // or just getClass
        (that canEqual this) &&
            x == that.x &&
            y == that.y
    case: that: Postion => false //this case can be removed
    case _ => false
 }

答案 1 :(得分:1)

有一个原因是自动生成的equals方法没有做你建议的事情。 canEqual约定是一个常见且记录良好的约定,因为它允许处理更广泛的常见用例。

在实现equals方法时,您并不总是想要排除所有子类,只有那些覆盖equals的子类。如果如你所描述的那样,有一个Position3D类扩展了Position,而Position3D有一个额外的字段z,它是Position3D equals方法的一部分,那么当然Position3D不应该等于任何正常的2D位置。

但是,如果由于某种原因用户想要实例化一个匿名的Position类?

,该怎么办?
val pos = new Position(1,2){}

trait Foo
val pos = new Position(1,2) with Foo

该职位应该被视为等于new Position(1,2)。如果混合功能是微不足道的,或仅仅针对某些特定的本地范围用例,则在某些情况下不允许这种平等可能是单调乏味的。要像其他响应所建议的那样other.getClass == classOf[Position],要求混合特征或由于某种原因创建匿名类的客户端API可能会发现他们创建的位置甚至不等于他们自己。

考虑以下代码:

class Position(val x:Int, val y:Int) {
  override def equals(other:Any) = other match {
    case o:Position if o.getClass==classOf[Position] && o.x==x && o.y==y => true
    case _ => false
  }
}
trait Foo
val p1 = new Position(1,2) with Foo
val p2 = new Position(1,2) with Foo
p1 == p2

结果为false

请参阅: http://www.artima.com/lejava/articles/equality.html