24

次のクラス階層があります。

class A
class B extends A
class C extends A

次に、これらのクラスのインスタンスを取る別のクラスと、次のように 2 つのケースのパターン マッチングが可能なメソッドがあります。

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

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

ただし、2 番目の case を優先してマッチングを解決する必要がある場合(B, C)は、それを解決しようと(B, B)し、クラス キャスト例外 that が発生し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)のシンタックス シュガーです。case ステートメントは が一致することを確認しますが、キャストに失敗します。Tuple2[B,C]Tuple2(B,C)Tuple2

あなたの場合、最も簡単な解決策は、タプルにラップするのではなく、「1」と「2」を個別に照合することです。

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 に答える