24

我有以下类层次结构:

class A
class B extends A
class C extends A

然后,有另一个类接受这些类的实例,并且有一个方法,其中可能有两种模式匹配情况,如下所示:

class D (one: A, two: A) {

  def work {
    (one, two) match {
      case (o, t): (B, B) => ... blablabla
      case (o, t): (B, C) => ... blablabla
      case _ =>
    }
  }
}

但是,当它应该解决匹配以支持第二种情况(B, C)时,它会尝试将其解析为(B, B)并提出类转换异常C cannot be cast to B。为什么?该怎么办?我怎么能解决这个问题?

4

3 回答 3

33

您的语法不太正确(无法编译)。

这虽然有效:

object Matcher extends App {

  class A
  class B extends A
  class C extends A

  class D(one: A, two: A) {

    def work {
      (one, two) match {
        case (o: B, t: B) => println("B")
        case (o: B, t: C) => println("C")
        case _ =>
      }
    }
  }

  val d1 = new D(new B, new B)
  val d2 = new D(new B, new C)

  d1.work
  //B
  d2.work
  //C
}
于 2012-08-16T12:31:18.693 回答
9

与往常一样,问题是擦除类型。(B,C)是 的语法糖,在运行时Tuple2[B,C]被擦除。Tuple2case 语句验证(B,C)匹配Tuple2,但随后无法转换它。

在您的情况下,最简单的解决方案是分别匹配“一”和“二”,而不是将它们包装在一个元组中:

one match {
  case o : B => two match {
    case p : C => ...
    case p : B => ...
  }
  ... 
}

它不是那么漂亮,但它不会遇到同样的问题。

编辑:实际上,我会选择 Brian Smith 的解决方案——在元组内部而不是外部匹配。它以类似的方式避免了这个问题,但看起来更好。

于 2012-08-16T12:31:20.113 回答
3

我使这个代码工作。
首先,我在您的类定义中添加了一个案例。

case class A
case class B extends A
case class C extends A

其次,我改变了work.

class D(one: A, two: A) {
  def work {
    (one, two) match {
      case (o: B, t: B) => println("BB")
      case (o: B, t: C) => println("BC")
      case (o: C, t: C) => println("CC")
      case _ => println("AA")
    }
  }
}

现在我得到了什么:

new D(B(),B()).work      => BB
new D(B(),C()).work      => BC
new D(C(),C()).work      => CC
new D(A(),B()).work      => AA

添加了case一个 apply 和一个 unapply 方法。

于 2012-08-16T12:30:17.493 回答