次のクラス階層があります。
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番目のケース(B, C)
を優先して一致を解決する必要がある場合は、(B, B)
として解決を試み、C cannot be cast to B
というクラスキャスト例外が発生します。どうして?何をすべきか?どうすればこれを回避できますか?
構文が正しくありません(コンパイルできません)。
これはうまくいきます:
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
}
問題は、いつものように、消去されたタイプです。 (B,C)
はTuple2[B,C]
の構文糖であり、実行時にTuple2
に消去されます。 caseステートメントは、(B,C)
がTuple2
と一致することを確認しますが、キャストに失敗します。
あなたの場合、最も簡単な解決策は、タプルでラップするのではなく、「1」と「2」を個別に照合することです:
one match {
case o : B => two match {
case p : C => ...
case p : B => ...
}
...
}
それほどきれいではありませんが、同じ問題が発生することはありません。
編集:実際には、私はブライアン・スミスのソリューションを使います-外部ではなくタプルの内部で一致します。同様の方法で問題を回避しますが、見栄えが良くなります。
私はこのコードを機能させました。
最初に、クラス定義にケースを追加しました。
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メソッドを追加します。