Я выполняю сопоставление с некоторыми классами case и хотел бы обрабатывать два случая аналогичным образом. Что-то вроде этого:
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"
}
}
Есть несколько способов, которые я могу видеть, чтобы достичь того, что вам нужно, если у вас есть общность между классами case. Во-первых, чтобы классы case расширили черту, которая объявляет общность, вторая - использовать структурный тип, который устраняет необходимость расширения классов case.
object MuliCase {
abstract class Foo
case object A extends Foo
trait SupportsS {val s: String}
type Stype = Foo {val s: String}
case class B(s:String) extends Foo
case class C(s:String) extends Foo
case class D(s:String) extends Foo with SupportsS
case class E(s:String) extends Foo with SupportsS
def matcher1(l: Foo): String = {
l match {
case A => "A"
case s: Stype => println(s.s); "B"
case _ => "default"
}
}
def matcher2(l: Foo): String = {
l match {
case A => "A"
case s: SupportsS => println(s.s); "B"
case _ => "default"
}
}
def main(args: Array[String]) {
val a = A
val b = B("B s value")
val c = C("C s value")
println(matcher1(a))
println(matcher1(b))
println(matcher1(c))
val d = D("D s value")
val e = E("E s value")
println(matcher2(d))
println(matcher2(e))
}
}
Метод структурного типа генерирует предупреждение об стирании, которое в настоящее время я не уверен, как его устранить.
Ну, это не имеет смысла, не так ли? B и C являются взаимоисключающими, поэтому привязка sb или sc привязана, но вы не знаете, что, поэтому вам потребуется дополнительная логика выбора, чтобы решить, что использовать (учитывая, что они были связаны с Option [String], а не строка). Так что ничего не получилось:
l match {
case A() => "A"
case B(sb) => "B(" + sb + ")"
case C(sc) => "C(" + sc + ")"
case _ => "default"
}
Или это:
l match {
case A() => "A"
case _: B => "B"
case _: C => "C"
case _ => "default"
}
args match { case Array("-x", hostArg) => (hostArg, true); case Array(hostArg, "-x") => (hostArg, true) }
Однако я вижу, что это не распространенный случай, и создание локального метода является альтернативой. Тем не менее, если альтернатива удобна, то нет смысла иметь альтернативные варианты. На самом деле, в некоторых диалектах ML у вас есть похожая особенность, и вы все еще можете связывать переменные, пока long (IIRC), так как каждая переменная связана с одним и тем же типом в обеих альтернативах.