Scala Multiple Type Pattern Matching

79

Ich frage mich, wie ich mehrere Mustermuster verwenden kann. Ich habe:

abstract class MyAbstract

case class MyFirst extends MyAbstract
case class MySecond extends MyAbstract
case class MyThird extends MyAbstract // shouldn't be matched and shouldn't call doSomething()

val x: MyAbstract = MyFirst

x match { 
 case a: MyFirst => doSomething()
 case b: MySecond => doSomething()
 case _ => doSomethingElse()
}

Also möchte ich etwas schreiben wie:

x match {
 case a @ (MyFirst | MySecond) => doSomething()
 case _ => doSomethingElse()
}

Ich habe in einem Tutorial eine ähnliche Konstruktion gesehen, aber es gibt mir einen Fehler:

pattern type is incompatible with expected type;
[error]  found   : object MyFirst
[error]  required: MyAbstract

Gibt es also eine Möglichkeit, in der case-Klausel einige verschiedene Typen zu definieren? Ich denke, das würde den Code schöner machen. Als ob ich 5 davon hätte, schreibe ich 5 Mal denselben Code (rufe doSomething () auf).

Danke im Voraus!

psisoyev
quelle
Ich denke, es ist ein XY-Problem. Sie haben eine gemeinsame Superklasse für alle doSomethingFälle, warum nicht die case a : MyAbstractdann ...?
Patryk Ćwiek
Entschuldigung, ich habe vergessen zu erwähnen, dass ich andere Klassen habe, die die MyAbstract-Klasse erweitern und doSomething nicht aufrufen sollten.
Psisoyev
Oh, OK, wollte das nur klarstellen :) Sie haben jetzt aber eine richtige Antwort auf Ihr Problem.
Patryk Ćwiek
mögliches Duplikat von Match mehrere Fälle Klassen in Scala
Nawfal

Antworten:

134

Ihnen fehlt die Klammer für Ihre Fallklassen. Fallklassen ohne Parameterlisten sind veraltet.

Versuche dies:

abstract class MyAbstract
case class MyFirst() extends MyAbstract
case class MySecond() extends MyAbstract

val x: MyAbstract = MyFirst()


x match {
   case aOrB @ (MyFirst() | MySecond()) => doSomething(aOrB)
   case _ => doSomethingElse()
}

Wenn Sie zu viele Parameter für Ihre Fallklassen haben und keine langen Foo(_,_,..)Muster schreiben möchten , dann vielleicht:

x match {
   case aOrB @ (_:MyFirst | _:MySecond) => doSomething(aOrB)
   case _ => doSomethingElse()
}

Oder nur:

x match {
   case _:MyFirst | _:MySecond => doSomething(x) // just use x instead of aOrB
   case _ => doSomethingElse(x)
}

Aber vielleicht wollten Sie nur Einzelfallobjekte?

abstract class MyAbstract
case object MyFirst extends MyAbstract
case object MySecond extends MyAbstract

val x: MyAbstract = MyFirst

x match {
   case aOrB @ (MyFirst | MySecond) => doSomething()
   case _ => doSomethingElse()
}
Faiz
quelle
1
Und es gibt keine Möglichkeit, Klammern zu vermeiden? Da ich ein paar Parameter habe und es hässlich wird: case a @ (MyFirst ( , _, _, _, _) | MySecond ( , _, _, _, _)) => doSomething ()
psisoyev
9
Haben Sie vermissen obj @ (_: MyFirst | _: MySecond)?
Jean-Philippe Pellet
Ich brauche objin Fällen, in denen ich es im doSomethingAnruf benutze . In meinem Fall wurde der Anruf von doSomethingnicht verwendet obj, daher brauche ich ihn nicht. Trotzdem danke für deinen Kommentar!
Psisoyev
@ Jean-PhilippePellet In der Tat habe ich. Lassen Sie mich meinen Beitrag bearbeiten, um ihn hinzuzufügen.
Faiz
1
Es wäre schön, wenn die Kompilierung intelligent genug wäre, um den nächstgelegenen gemeinsamen Typ zu finden, anstatt standardmäßig den Eingabetyp zu verwenden.
Nilskp