1. ホーム
  2. scala

[解決済み] scala で複数の case class をマッチングさせる

2022-11-30 20:55:24

質問

いくつかのケースクラスに対してマッチングを行っているのですが、2つのケースを同じように処理したいのです。以下のようなものです。

abstract class Foo
case class A extends Foo
case class B(s:String) extends Foo
case class C(s:String) extends Foo


def matcher(l: Foo): String = {
  l match {
    case A() => "A"
    case B(sb) | C(sc) => "B"
    case _ => "default"
  }
}

しかし、これを実行すると、エラーが発生します。

(fragment of test.scala):10: error: illegal variable in pattern alternative
    case B(sb) | C(sc) => "B"

BとCの定義からパラメータを削除すると動作するようになるのですが、どのようにパラメータとマッチングさせればよいのでしょうか?

どのように解決するのですか?

Stringパラメータの値は気にせず、BとCを同じように扱いたいようですね、では。

def matcher(l: Foo): String = {
  l match {
    case A() => "A"
    case B(_) | C(_) => "B"
    case _ => "default"
  }
}

どうしても、どうしても、どうしてもパラメータを抽出して同じコードブロックで扱いたい場合は

def matcher(l: Foo): String = {
  l match {
    case A() => "A"
    case bOrC @ (B(_) | C(_)) => {
      val s = bOrC.asInstanceOf[{def s: String}].s // ugly, ugly
      "B(" + s + ")"
    }
    case _ => "default"
  }
}

メソッドに因数分解した方がよっぽど綺麗な気がするけど。

def doB(s: String) = { "B(" + s + ")" }

def matcher(l: Foo): String = {
  l match {
    case A() => "A"
    case B(s) => doB(s)
    case C(s) => doB(s)
    case _ => "default"
  }
}